PAGE 118,121
TITLE POST ----- 01/10/86  SYSTEM POST AND BIOS PROCEDURES

	PUBLIC	A1
	PUBLIC	BEEP
	PUBLIC	CONF_TBL
	PUBLIC	CRT_CHAR_GEN
	PUBLIC	DDS
	PUBLIC	DISK_BASE
	PUBLIC	M5
	PUBLIC	M6
	PUBLIC	M7
	PUBLIC	MD_TBL1
	PUBLIC	MD_TBL2
	PUBLIC	MD_TBL3
	PUBLIC	MD_TBL4
	PUBLIC	MD_TBL5
	PUBLIC	MD_TBL6
	PUBLIC	P_O_R
	PUBLIC	RESET
	PUBLIC	VIDEO_PARMS
	PUBLIC	WAITF

	EXTRN	CASSETTE_IO_1:NEAR
	EXTRN	DISKETTE_IO_1:NEAR
	EXTRN	DISK_INT_1:NEAR
	EXTRN	DSKETTE_SETUP:NEAR
	EXTRN	KB_INT_1:NEAR
	EXTRN	KEYBOARD_IO_1:NEAR
	EXTRN	NEC_OUTPUT:NEAR
	EXTRN	PRINTER_IO_1:NEAR
	EXTRN	RESULTS:NEAR
	EXTRN	RS232_IO_1:NEAR
	EXTRN	SEEK:NEAR
	EXTRN	VIDEO_IO_1:NEAR

	EXTRN	SET_MODE:NEAR
	EXTRN	SET_CTYPE:NEAR
	EXTRN	SET_CPOS:NEAR
	EXTRN	READ_CURSOR:NEAR
	EXTRN	READ_LPEN:NEAR
	EXTRN	ACT_DISP_PAGE:NEAR
	EXTRN	SCROLL_UP:NEAR
	EXTRN	SCROLL_DOWN:NEAR
	EXTRN	READ_AC_CURRENT:NEAR
	EXTRN	WRITE_AC_CURRENT:NEAR
	EXTRN	WRITE_C_CURRENT:NEAR
	EXTRN	SET_COLOR:NEAR
	EXTRN	WRITE_DOT:NEAR
	EXTRN	READ_DOT:NEAR
	EXTRN	WRITE_TTY:NEAR
	EXTRN	VIDEO_STATE:NEAR
.XLIST
INCLUDE POSTEQU.INC
INCLUDE DSEG.INC
.LIST
;----------------------------------------------------------------
;	THE  BIOS ROUTINES ARE MEANT TO BE ACCESSED THROUGH	;
;	SOFTWARE INTERRUPTS ONLY.  ANY ADDRESSES PRESENT IN	;
;	THE LISTINGS  ARE INCLUDED  ONLY FOR  COMPLETENESS,	;
;	NOT FOR  REFERENCE.   APPLICATIONS WHICH  REFERENCE	;
;	ABSOLUTE   ADDRESSES   WITHIN	THE   CODE  SEGMENT	;
;	VIOLATE THE STRUCTURE AND DESIGN OF BIOS.		;
;----------------------------------------------------------------
;----------------------------------------
;	ROM RESIDENT CODE		:
;----------------------------------------
CODE	SEGMENT BYTE	PUBLIC

	DB	01FFFH	DUP	(0CCH)	; FILL UNUSED LOCATIONS WITH INTERRUPT 3
;	ORG	0E000H
	ORG	0
	DB	'62X0890 COPR. IBM 1986'        ; COPYRIGHT NOTICE
;------------------------------------------------
;	INITIAL RELIABILITY TESTS -- PHASE 1	:
;------------------------------------------------

	ASSUME	  CS:CODE,SS:CODE,ES:ABS0,DS:DATA

C1	DW	C11		; RETURN ADDRESS
C2	DW	C24		; RETURN ADDRESS FOR DUMMY STACK
F3B	DB	' KB OK',13     ; KB FOR MEMORY SIZE
;------------------------------------------------------------------------
;	LOAD A BLOCK OF TEST CODE THROUGH THE KEYBOARD PORT		:
;	FOR MANUFACTURING TEST. 					:
;	THIS ROUTINE WILL LOAD A TEST (MAX LENGTH=FAFFH) THROUGH	:
;	THE KEYBOARD PORT. CODE WILL BE LOADED AT LOCATION		:
;	0000:0500. AFTER LOADING, CONTROL WILL BE TRANSFERED		:
;	TO LOCATION 0000:0500. STACK WILL BE LOCATED JUST BELOW 	:
;	THE TEST CODE. THIS ROUTINE ASSUMES THAT THE FIRST 2		:
;	BYTES TRANSFERED CONTAIN THE COUNT OF BYTES TO BE LOADED	:
;	(BYTE 1=COUNT LOW, BYTE 2=COUNT HI.)				:
;------------------------------------------------------------------------

;----- FIRST, GET THE COUNT

MFG_BOOT:
	CALL	SP_TEST 		; GET COUNT LOW
	MOV	BH,BL			; SAVE IT
	CALL	SP_TEST 		; GET COUNT HI
	MOV	CH,BL
	MOV	CL,BH			; CX NOW HAS COUNT
	CLI
	CLD				; SET DIR. FLAG TO INCREMENT
	MOV	AL,0FDH 		; UNMASK K/B INTERRUPT
	OUT	INTA01,AL
	MOV	DI,0500H		; SET TARGET OFFSET (DS=0000)
	MOV	AL,0AH			; SEND READ INT. REQUEST REG. CMD
	OUT	INTA00,AL
	MOV	DX,PORT_B		; SET UP PORT B ADDRESS
TST:
	MOV	AL,0CCH
	OUT	DX,AL
	MOV	AL,4CH
	OUT	DX,AL
	DEC	DX			; POINT DX AT ADDR. 60 (KB DATA)
TST1:
	IN	AL,INTA00		; GET IRR REG
	AND	AL,02H			; KB REQUEST PENDING?
	JZ	TST1			; LOOP TILL DATA PRESENT
	IN	AL,DX			; GET DATA
	STOSB				; STORE IT
	INC	DX			; POINT DX BACK AT PORT B (61)
	LOOP	TST			; LOOP TILL ALL BYTES READ
	JMP	@MFG_TEST_RTN		; FAR JUMP TO CODE THAT WAS JUST
					; LOADED
;----------------------------------------
;	8088 PROCESSOR TEST		:
; DESCRIPTION				:
;	VERIFY 8088 FLAGS, REGISTERS	:
;	AND CONDITIONAL JUMPS		:
;----------------------------------------
	ASSUME	CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
;	ORG	0E05BH
	ORG	0005BH
RESET:
START:	CLI				; DISABLE INTERRUPTS
	MOV	AH,0D5H 		; SET SF, CF, ZF, AND AF FLAGS ON
	SAHF
	JNC	ERR01			; GO TO ERR ROUTINE IF CF NOT SET
	JNZ	ERR01			; GO TO ERR ROUTINE IF ZF NOT SET
	JNP	ERR01			; GO TO ERR ROUTINE IF PF NOT SET
	JNS	ERR01			; GO TO ERR ROUTINE IF SF NOT SET
	LAHF				; LOAD FLAG IMAGE TO AH
	MOV	CL,5			; LOAD CNT REG WITH SHIFT CNT
	SHR	AH,CL			; SHIFT AF INTO CARRY BIT POS
	JNC	ERR01			; SO TO ERR ROUTINE IF AF NOT SET
	MOV	AL,40H			; SET THE OF FLAG ON
	SHL	AL,1			; SETUP FOR TESTING
	JNO	ERR01			; GO TO ERR ROUTINE IF OF NOT SET
	XOR	AH,AH			; SET AH = 0
	SAHF				; CLEAR SF, CF, ZF, AND PF
	JBE	ERR01			; GO TO ERR ROUTINE IF CF ON
					; OR TO TO ERR ROUTINE IF ZF ON
	JS	ERR01			; GO TO ERR ROUTINE IF SF ON
	JP	ERR01			; GO TO ERR ROUTINE IF PF ON
	LAHF				; LOAD FLAG IMAGE TO AH
	SHR	AH,CL			; SHIFT AH INTO CARRY BIT POS
	JC	ERR01			; GO TO ERR ROUTINE IF ON
	SHL	AH,1			; CHECK THAT OF IS CLEAR
	JO	ERR01			; GO TO ERR ROUTINE IF ON

;----- READ/WRITE THE 8088 GENERAL AND SEGMENTATION REGISTERS
;      WITH ALL ONE'S AND ZEROES'S.

	MOV	AX,0FFFFH		; SETUP ONE'S PATTERN IN AX
	STC
C8:	MOV	DS,AX			; WRITE PATTERN TO ALL REGS
	MOV	BX,DS
	MOV	ES,BX
	MOV	CX,ES
	MOV	SS,CX
	MOV	DX,SS
	MOV	SP,DX
	MOV	BP,SP
	MOV	SI,BP
	MOV	DI,SI
	JNC	C9			; TST1A
	XOR	AX,DI			; PATTERN MAKE IT THRU ALL REGS
	JNZ	ERR01			; NO - GO TO ERR ROUTINE
	CLC
	JMP	C8
C9:					; TST1A
	OR	AX,DI			; ZERO PATTERN MAKE IT THRU?
	JZ	C10			; YES - GO TO NEXT TEST
ERR01:	HLT				; HALT SYSTEM
;----------------------------------------
;	ROS CHECKSUM TEST I		:
;DESCRIPTION				:
;	A CHECKSUM IS DONE FOR THE 8K	:
;	ROS MODULE CONTAINING POD AND	:
;	BIOS.				:
;----------------------------------------
C10:
					; ZERO IN AL ALREADY
	OUT	0A0H,AL 		; DISABLE NMI INTERRUPTS
	OUT	83H,AL			; INITIALIZE DMA PAGE REG
	MOV	DX,3D8H
	OUT	DX,AL			; DISABLE COLOR VIDEO
	INC	AL
	MOV	DL,0B8H
	OUT	DX,AL			; DISABLE B/W VIDEO,EN HIGH RES
	MOV	AL,89H			; SET 8255 FOR B,A=OUT, C=IN
	OUT	CMD_PORT,AL
	MOV	AL,10100101B
					; ENABLE PARITY CHECKERS AND
	OUT	PORT_B,AL		; PULL KB CLOCK HI, TRI-STATE
					; KEYBOARD INPUTS,ENABLE HIGH
					; BANK OF SWITCHES->PORT C(0-3)
	MOV	AL,01H			; <><><><><><><><><><><><>
	OUT	PORT_A,AL		; <><><>CHECKPOINT 1<><><>
	MOV	AX,CS			; SETUP SS SEG REG
	MOV	SS,AX
	MOV	DS,AX			; SET UP DATA SEG TO POINT TO
					; ROM ADDRESS
	CLD				; SET DIRECTION FLAG TO INC.
	ASSUME	SS:CODE
	MOV	BX,00000H		; SETUP STARTING ROS ADDR
	MOV	SP,OFFSET C1		; SETUP RETURN ADDRESS
	JMP	ROS_CHECKSUM
C11:	JNE	ERR01			; HALT SYSTEM IF ERROR
PAGE
;--------------------------------------------------------
;	8237 DMA INITIALIZATION CHANNEL REGISTER TEST	:
;DESCRIPTION						:
;	DISABLE THE 8237 DMA CONTROLLER.  VERIFY THAT	:
;	TIMER 1 FUNCTIONS OK. WRITE/READ THE CURRENT	:
;	ADDRESS AND WORD COUNT REGISTERS FOR ALL	:
;	CHANNELS.  INITIALIZE AND START DMA FOR MEMORY	:
;	REFRESH.					:
;--------------------------------------------------------

;----- DISABLE DMA CONTROLLER

	MOV	AL,02H			; <><><><><><><><><><><><>
	OUT	PORT_A,AL		; <><><>CHECKPOINT 2<><><>
	MOV	AL,04			; DISABLE DMA CONTROLLER
	OUT	DMA08,AL

;----- VERIFY THAT TIMER 1 FUNCTIONS OK

	MOV	AL,54H			; SEL TIMER 1,LSB,MODE 2
	OUT	TIMER+3,AL
	MOV	AL,CL			; SET INITIAL TIMER CNT TO 0
	OUT	TIMER+1,AL
C12:					; TIMER1_BITS_ON
	MOV	AL,40H			; LATCH TIMER 1 COUNT
	OUT	TIMER+3,AL
	CMP	BL,0FFH 		; YES - SEE IF ALL BITS GO OFF
	JE	C13			; TIMER1_BITS_OFF
	IN	AL,TIMER+1		; READ TIMER 1 COUNT
	OR	BL,AL			; ALL BITS ON IN TIMER
	LOOP	C12			; TIMER1_BITS_ON
	HLT				; TIMER 1 FAILURE, HALT SYS
C13:					; TIMER1_BITS_OFF
	MOV	AL,BL			; SET TIMER 1 CNT
	SUB	CX,CX
	OUT	TIMER+1,AL
C14:					; TIMER_LOOP
	MOV	AL,40H			; LATCH TIMER 1 COUNT
	OUT	TIMER+3,AL
	NOP				; DELAY FOR TIMER
	NOP
	IN	AL,TIMER+1		; READ TIMER 1 COUNT
	AND	BL,AL
	JZ	C15			; GO TO WRAP_DMA_REG
	LOOP	C14			; TIMER_LOOP
	HLT				; TIMER ERROR - HALT SYSTEM

;----- INITIALIZE TIMER 1 TO REFRESH MEMORY

C15:	MOV	AL,03H			; <><><><><><><><><><><><>
	OUT	PORT_A,AL		; <><><>CHECKPOINT 3<><><>
					; WRAP_DMA_REG
	OUT	DMA+0DH,AL		; SEND MASTER CLEAR TO DMA

;----- WRAP DMA CHANNELS ADDRESS AND COUNT REGISTERS

	MOV	AL,0FFH 		; WRITE PATTERN FF TO ALL REGS
C16:	MOV	BL,AL			; SAVE PATTERN FOR COMPARE
	MOV	BH,AL
	MOV	CX,8			; SETUP LOOP CNT
	MOV	DX,DMA			; SETUP I/O PORT ADDR OF REG
C17:	OUT	DX,AL			; WRITE PATTERN TO REG, LSB
	PUSH	AX			; SATISIFY 8237 I/O TIMINGS
	OUT	DX,AL			; MSB OF 16 BIT REG
	MOV	AL,01H			; AL TO ANOTHER PAT BEFORE RD
	IN	AL,DX			; READ 16-BIT DMA CH REG, LSB
	MOV	AH,AL			; SAVE LSB OF 16-BIT REG
	IN	AL,DX			; READ MSB OF DMA CH REG
	CMP	BX,AX			; PATTERN READ AS WRITTEN?
	JE	C18			; YES - CHECK NEXT REG
C17A:
	HLT				; NO - HALT THE SYSTEM
C18:					; NXT_DMA_CH
	INC	DX			; SET I/O PORT TO NEXT CH REG
	STC
	LOOP	C17			; WRITE PATTERN TO NEXT REG
	JNC	C17A			; IF CARRY NOT SET HALT SYSTEM
	INC	AL			; SET PATTERN TO 0
	JZ	C16			; WRITE TO CHANNEL REGS

;----- INITIALIZE AND START DMA FOR MEMORY REFRESH.

	MOV	DS,BX			; SET UP ABS0 INTO DS AND ES
	MOV	ES,BX
	ASSUME	DS:ABS0,ES:ABS0
	MOV	AL,0FFH 		; SET CNT OF 64K FOR RAM REFRESH
	OUT	DMA+1,AL
	PUSH	AX
	OUT	DMA+1,AL
	MOV	AL,058H 		; SET DMA MODE,CH 0,RD.,AUTOINT
	OUT	DMA+0BH,AL		; WRITE DMA MODE REG
	MOV	AL,0			; ENABLE DMA CONTROLLER
	MOV	CH,AL			; SET COUNT HIGH=00
	OUT	DMA+8,AL		; SETUP DMA COMMAND REG
	PUSH	AX
	OUT	DMA+10,AL		; ENABLE DMA CH 0
	MOV	AL,18			; START TIMER 1
	OUT	TIMER+1,AL
	MOV	AL,41H			; SET MODE FOR CHANNEL 1
	OUT	DMA+0BH,AL
	PUSH	AX
	IN	AL,DMA+08		; GET DMA STATUS
	AND	AL,00010000B		; IS TIMER REQUEST THERE?
	JZ	C18C			; (IT SHOULD'T BE)
	HLT				; HALT SYS.(HOT TIMER 1 OUTPUT)
C18C:	MOV	AL,42H			; SET MODE FOR CHANNEL 2
	OUT	DMA+0BH,AL
	MOV	AL,43H			; SET MODE FOR CHANNEL 3
	OUT	DMA+0BH,AL
PAGE
;------------------------------------------------
;	BASE 16K READ/WRITE STORAGE TEST	:
;DESCRIPTION					:
;	WRITE/READ/VERIFY DATA PATTERNS 	:
;	FF,55,AA,01, AND 00 TO 1ST 32K OF	:
;	STORAGE. VERIFY STORAGE ADDRESSABILITY. :
;------------------------------------------------

	LODSW				; ALLOW RAM CHARGE TIME.
	LODSW
	LODSW
	LODSW

;----- DETERMINE MEMORY SIZE AND FILL MEMORY WITH DATA

	MOV	BX,DATA_WORD[@RESET_FLAG-DATA40] ; SAVE 'RESET_FLAG' IN BX
	MOV	BP,DATA_WORD[@KB_FLAG_3-DATA40] ; SAVE KEYBOARD TYPE
	CMP	BP,KBX			; IS THE KBX BIT THE ONLY ONE ON?
	JE	CLR_STG 		; IF NOT THEN THIS MUST BE A P.O.R.
	SUB	BP,BP			; IF P.O.R. THEN INITIALIZE THIS TO ZERO
CLR_STG:
	MOV	CX,08000H		; SET FOR 32K WORDS
	SUB	AX,AX			; MAKE AX=0000
	REP	STOSW			; STORE 8K WORDS OF 0000
	CMP	BX,1234H		; WARM START?
	JE	HOW_BIG
	MOV	SP,OFFSET C2
	MOV	CX,08000H		; SET FOR 32K WORDS
	JMP	STGTST_CNT
C24:	JE	HOW_BIG 		; STORAGE OK, DETERMINE SIZE
	MOV	BL,04H			; <><><><><><><><><><><><>
C24A:	OUT	PORT_A,AL		; <><><>CHECKPOINT 4<><><>
	SUB	CX,CX			; BASE RAM FAILURE - HANG
C24B:	LOOP	C24B			; FLIPPING BETWEEN 04 AND
	XCHG	AX,BX			; FAILING BIT PATTERN
	JMP	C24A
HOW_BIG:
	MOV	DATA_WORD[@RESET_FLAG-DATA40],BX	; RESTORE RESET FLAG
	MOV	DATA_WORD[@KB_FLAG_3-DATA40],BP ; RESTORE RESET FLAG
	SUB	BP,BP			; BP IS USED LATER AS AN ERROR INDICATOR
	MOV	DX,1000H
	MOV	BX,64
FILL_LOOP:
	MOV	ES,DX			; SET SEG. REG.
	SUB	DI,DI
	MOV	AX,0AA55H		; TEST PATTERN
	MOV	ES:[DI],AX		; SEND PATTERN TO MEM.
	CLD
	XOR	AX,ES:[DI]		; COMPARE PATTERNS
	CLD
	JNZ	HOW_BIG_END		; GO END IF NO COMPARE
	MOV	CX,2000H		; SET COUNT FOR 8K WORDS
	REP	STOSW			; FILL 8K WORDS
	ADD	DX,400H 		; POINT TO NEXT 16KB BLOCK
	ADD	BX,16			; BUMP COUNT BY 16KB
	CMP	DH,0A0H 		; TOP OF RAM AREA YET? (A0000)
	JNZ	FILL_LOOP
HOW_BIG_END:
	MOV	DATA_WORD[@MEMORY_SIZE-DATA40],BX	; SAVE MEMORY SIZE

;----- SETUP STACK SEG AND SP

	MOV	AX,STACK_SS		; GET STACK VALUE
	MOV	SS,AX			; SET THE STACK UP
	MOV	SP,OFFSET TOS		; STACK IS READY TO GO
;--------------------------------------------------------
;	INITIALIZE THE 8259 INTERRUPT CONTROLLER CHIP	:
;--------------------------------------------------------
C25:	MOV	AL,13H			; ICW1 - EDGE, SNGL, ICW4
	OUT	INTA00,AL
	MOV	AL,8			; SETUP ICW2 - INT TYPE 8 (8-F)
	OUT	INTA01,AL
	MOV	AL,9			; SETUP ICW4 - BUFFRD,8086 MODE
	OUT	INTA01,AL
	MOV	AL,0FFH 		; MASK ALL INTS. OFF
	OUT	INTA01,AL		; (VIDEO ROUTINE ENABLES INTS.)

;----- SET UP THE INTERRUPT VECTORS TO TEMP INTERRUPT

	PUSH	DS
	MOV	CX,32			; FILL ALL 32 INTERRUPTS
	SUB	DI,DI			; FIRST INTERRUPT LOCATION
	MOV	ES,DI			; SET ES=0000 ALSO
D3:	MOV	AX,OFFSET D11		; MOVE ADDR OF INTR PROC TO TBL
	STOSW
	MOV	AX,CS			; GET ADDR OF INTR PROC SEG
	STOSW
	LOOP	D3			; VECTBL0

;----- ESTABLISH BIOS SUBROUTINE CALL INTERRUPT VECTORS

	MOV	DI,OFFSET @VIDEO_INT	; SETUP ADDR TO INTR AREA
	PUSH	CS
	POP	DS			; SETUP ADDR OF VECTOR TABLE
	MOV	SI,OFFSET VECTOR_TABLE+16	; START WITH VIDEO ENTRY
	MOV	CX,16
D3A:	MOVSW				; MOVE VECTOR TABLE TO RAM
	INC	DI			; SKIP SEGMENT POINTER
	INC	DI
	LOOP	D3A
;------------------------------------------------
;	DETERMINE CONFIGURATION AND MFG. MODE	:
;------------------------------------------------

	POP	DS
	PUSH	DS			; RECOVER DATA SEG POINTER
	MOV	WORD PTR @EXT_PTR+2,0000	;SEGMENT FOR VIDEO EXTENSION
	IN	AL,PORT_C		; GET SWITCH INFO
	AND	AL,00001111B		; ISOLATE SWITCHES
	MOV	AH,AL			; SAVE
	MOV	AL,10101101B		; ENABLE OTHER BANK OF SWS.
	OUT	PORT_B,AL
	NOP
	IN	AL,PORT_C
	MOV	CL,4
	ROL	AL,CL			; ROTATE TO HIGH NIBBLE
	AND	AL,11110000B		; ISOLATE
	OR	AL,AH			; COMBINE WITH OTHER BANK
	SUB	AH,AH
	MOV	DATA_WORD[@EQUIP_FLAG-DATA40],AX	; SAVE SWITCH INFO
	MOV	AL,99H
	OUT	CMD_PORT,AL
	CALL	KBD_RESET		; SEE IF MFG. JUMPER IN
	CMP	BL,0EAH 		; IS THIS THE EXTENDED KEYBOARD?
	JNE	KBX1			; IF NOT THEN LEAVE THE FLAG ALONE
	MOV	DATA_AREA[@KB_FLAG_3-DATA40],KBX  ; EXTENDED KEYBOARD
	JMP	SHORT E6		; DONE WITH KEYBOARD HERE
KBX1:
	CMP	BL,0AAH 		; KEYBOARD PRESENT?
	JE	E6
	CMP	BL,065H 		; LOAD MFG. TEST REQUEST?
	JNE	D3B
	JMP	MFG_BOOT		; GO TO BOOTSTRAP IF SO
D3B:
	OR	BL,BL			; MFG PLUG IN?
	JNZ	E6			; NO
	MOV	AL,38H
	OUT	PORT_B,AL
	NOP
	NOP
	IN	AL,PORT_A
	AND	AL,0FFH 		; WAS DATA LINE GROUNDED
	JNZ	E6
	INC	DATA_AREA[@MFG_TST-DATA40]	; SET MANUFACTURING TEST FLAG

;--------------------------------------------------------
;	INITIALIZE AND START CRT CONTROLLER (6845)	:
;	TEST VIDEO READ/WRITE STORAGE.			:
;DESCRIPTION						:
;	RESET THE VIDEO ENABLE SIGNAL.			:
;	SELECT ALPHANUMERIC MODE, 40 * 25, B & W.	:
;	READ/WRITE DATA PATTERNS TO STG. CHECK STG	:
;	ADDRESSABILITY. 				:
; ERROR = 1 LONG AND 2 SHORT BEEPS			:
;--------------------------------------------------------
E6:
	MOV	AX,DATA_WORD[@EQUIP_FLAG-DATA40]	; GET SENSE SWITCH INFO
	PUSH	AX			; SAVE IT
	MOV	AL,30H
	MOV	DATA_WORD[@EQUIP_FLAG-DATA40],AX
	SUB	AH,AH
	INT	10H			; SEND INIT TO B/W CARD
	MOV	AL,20H
	MOV	DATA_WORD[@EQUIP_FLAG-DATA40],AX
	SUB	AH,AH
	INT	10H			; AND INIT COLOR CARD
	POP	AX			; RECOVER REAL SWITCH INFO
	MOV	DATA_WORD[@EQUIP_FLAG-DATA40],AX	; RESTORE IT
					; AND CONTINUE
	AND	AL,30H			; ISOLATE VIDEO SWS
	JNZ	E7			; VIDEO SWS SET TO 0?
	MOV	DI,OFFSET @VIDEO_INT	; SET INT 10H TO DUMMY
	MOV	WORD PTR [DI],OFFSET DUMMY_RETURN	; RET IF NO VIDEO CARD
	JMP	E18_1			; BYPASS VIDEO TEST
E7:					; TEST_VIDEO:
	CMP	AL,30H			; B/W CARD ATTACHED?
	JE	E8			; YES - SET MODE FOR B/W CARD
	MOV	AH,1			; SET COLOR MODE FOR COLOR CD
	CMP	AL,20H			; 80X25 MODE SELECTED?
	JNE	E8			; NO - SET MODE FOR 40X25
	MOV	AH,3			; SET MODE FOR 80X25
E8:	XCHG	AH,AL			; SET_MODE:
	PUSH	AX			; SAVE VIDEO MODE ON STACK
	SUB	AH,AH			; INITIALIZE TO ALPHANUMERIC MD
	INT	10H			; CALL VIDEO_IO
	POP	AX			; RESTORE VIDEO SENSE SWS IN AH
	PUSH	AX			; RESAVE VALUE
	MOV	BX,0B000H		; BEG VIDEO RAM ADDR B/W CD
	JMP	SHORT E8A

;----- UNNATURAL ACT FOR ADDRESS COMPATIBILITY

;	ORG	0E2C3H
	ORG	002C3H
NMI_INT:
	JMP	NMI_INT_1

E8A:
	MOV	DX,3B8H 		; MODE REG FOR B/W
	MOV	CX,2048 		; RAM WORD CNT FOR B/W CD
	MOV	AL,1			; SET MODE FOR B/W CARD
	CMP	AH,30H			; B/W VIDEO CARD ATTACHED?
	JE	E9			; YES - GO TEST VIDEO STG
	MOV	BH,0B8H 		; BEG VIDEO RAM ADDR COLOR CD
	MOV	DX,3D8H 		; MODE REG FOR COLOR CD
	MOV	CH,20H			; RAM WORD CNT FOR COLOR CD
	DEC	AL			; SET MODE TO 0 FOR COLOR CD
E9:					; TEST_VIDEO_STG:
	OUT	DX,AL			; DISABLE VIDEO FOR COLOR CD
	CMP	DATA_WORD[@RESET_FLAG-DATA40],1234H ; POD INIT BY KBD RESET?
	MOV	ES,BX			; POINT ES TO VIDEO RAM STG
	JE	E10			; YES - SKIP VIDEO RAM TEST
	MOV	DS,BX			; POINT DS TO VIDEO RAM STG
	ASSUME	DS:NOTHING,ES:NOTHING
	CALL	STGTST_CNT		; GO TEST VIDEO R/W STG
	JNE	E17			; R/W STG FAILURE - BEEP SPK
;------------------------------------------------
;	SETUP VIDEO DATA ON SCREEN FOR VIDEO	:
;	LINE TEST.				:
; DESCRIPTION					:
;	ENABLE VIDEO SIGNAL AND SET MODE.	:
;	DISPLAY A HORIZONTAL BAR ON SCREEN.	:
;------------------------------------------------
E10:
	POP	AX			; GET VIDEO SENSE SWS (AH)
	PUSH	AX			; SAVE IT
	MOV	AH,0			; ENABLE VIDEO AND SET MODE
	INT	10H			; VIDEO
	MOV	AX,7020H		; WRT BLANKS IN REVERSE VIDEO

	SUB	DI,DI			; SETUP STARTING LOC
	MOV	CX,40			; NO. OF BLANKS TO DISPLAY
	REP	STOSW			; WRITE VIDEO STORAGE
;----------------------------------------
;	CRT INTERFACE LINES TEST	:
;DESCRIPTION				:
;	SENSE ON/OFF TRANSITION OF THE	:
;	VIDEO ENABLE AND HORIZONTAL	:
;	SYNC LINES.			:
;----------------------------------------
	POP	AX			; GET VIDEO SENSE SW INFO
	PUSH	AX			; SAVE IT
	CMP	AH,30H			; B/W CARD ATTACHED?
	MOV	DX,03BAH		; SETUP ADDR OF BW STATUS PORT
	JE	E11			; YES - GO TEST LINES
	MOV	DX,03DAH		; COLOR CARD IS ATTACHED
E11:					; LINE_TST:
	MOV	AH,8
E12:					; OFLOOP_CNT:
	SUB	CX,CX
E13:
	IN	AL,DX			; READ CRT STATUS PORT
	AND	AL,AH			; CHECK VIDEO/HORZ LINE
	JNZ	E14			; ITS ON - CHECK IF IT GOES OFF
	LOOP	E13			; LOOP TILL ON OR TIMEOUT
	JMP	SHORT E17		; GO PRINT ERROR MSG
E14:
	SUB	CX,CX
E15:
	IN	AL,DX			; READ CRT STATUS PORT
	AND	AL,AH			; CHECK VIDEO/HORZ LINE
	JZ	E16			; ITS ON - CHECK NEXT LINE
	LOOP	E15			; LOOP IF OFF TILL IT GOES ON
E17:					; CRT_ERR:
	ASSUME	DS:ABS0
	XOR	DX,DX
	MOV	DS,DX			; SET UP ABS0 INTO DS
	MOV	DATA_AREA[@MFG_ERR_FLAG-DATA40],06H
	MOV	DX,102H
	CALL	ERR_BEEP		; GO BEEP SPEAKER
	JMP	SHORT E18
E16:					; NXT_LINE:
	MOV	CL,3			; GET NEXT BIT TO CHECK
	SHR	AH,CL			;
	JNZ	E12			; GO CHECK HORIZONTAL LINE
E18:					;  DISPLAY_CURSOR:
	POP	AX			; GET VIDEO SENSE SWS (AH)
	MOV	AH,0			; SET MODE AND DISPLAY CURSOR
	INT	10H			; CALL VIDEO I/O PROCEDURE
E18_1:
	MOV	DX,0C000H		; SEE IF ADVANCED VIDEO CARD
E18A:
	MOV	DS,DX			; IS PRESENT
	SUB	BX,BX
	MOV	AX,[BX] 		; GET FIRST 2 LOCATIONS
	CLD
	CLD				; LET BUS SETTLE
	CMP	AX,0AA55H		; PRESENT?
	JNZ	E18B			; NO? GO LOOK FOR OTHER MODULES
	CALL	ROM_CHECK		; GO SCAN MODULE
	JMP	SHORT E18C
E18B:
	ADD	DX,0080H		; POINT TO NEXT 2K BLOCK
E18C:
	CMP	DX,0C800H		; TOP OF VIDEO ROM AREA YET?
	JL	E18A			; GO SCAN FOR ANOTHER MODULE
;--------------------------------------------------------
;	8259 INTERRUPT CONTROLLER TEST			:
;DESCRIPTION						:
;	READ/WRITE THE INTERRUPT MASK REGISTER (IMR)	:
;	WITH ALL ONES AND ZEROES. ENABLE SYSTEM 	:
;	INTERRUPTS.  MASK DEVICE INTERRUPTS OFF. CHECK	:
;	FOR HOT INTERRUPTS (UNEXPECTED).		:
;--------------------------------------------------------
	ASSUME	DS:ABS0
C21:	POP	DS

;----- TEST THE IMR REGISTER

C21A:	MOV	DATA_AREA[@MFG_ERR_FLAG-DATA40],05H
					; <><><><><><><><><><><><>
					; <><><>CHECKPOINT 5<><><>
	MOV	AL,0			; SET IMR TO ZERO
	OUT	INTA01,AL
	IN	AL,INTA01		; READ IMR
	OR	AL,AL			; IMR = 0?
	JNZ	D6			; GO TO ERR ROUTINE IF NOT 0
	MOV	AL,0FFH 		; DISABLE DEVICE INTERRUPTS
	OUT	INTA01,AL		; WRITE TO IMR
	IN	AL,INTA01		; READ IMR
	ADD	AL,1			; ALL IMR BITS ON?
	JNZ	D6			; NO - GO TO ERR ROUTINE

;----- CHECK FOR HOT INTERRUPTS

;----- INTERRUPTS ARE MASKED OFF.  CHECK THAT NO INTERRUPTS OCCUR

	MOV	DATA_AREA[@INTR_FLAG-DATA40],AL ; CLEAR INTERRUPT FLAG
	STI				; ENABLE EXTERNAL INTERRUPTS
	SUB	CX,CX			; WAIT 1 SEC FOR ANY INTRS THAT
D4:
	LOOP	D4			; MIGHT OCCUR
D5:
	LOOP	D5
	CMP	DATA_AREA[@INTR_FLAG-DATA40],00H	; ANY INTERRUPTS OCCUR?
	JZ	D7			; NO - GO TO NEXT TEST
D6:
	MOV	SI,OFFSET E0		; DISPLAY 101 ERROR
	CALL	E_MSG
	CLI
	HLT				; HALT THE SYSTEM
PAGE
;--------------------------------------------------------
;	8253 TIMER CHECKOUT				:
;DESCRIPTION						:
;	VERIFY THAT THE SYSTEM TIMER (0) DOESN'T COUNT  :
;	TOO FAST OR TOO SLOW.				:
;--------------------------------------------------------
D7:
	MOV	DATA_AREA[@MFG_ERR_FLAG-DATA40],02H
					; <><><><><><><><><><><><><><><><>
					; <><><>TIMER CHECKPOINT (2)<><><>
	MOV	AL,0FEH 		; MASK ALL INTRS EXCEPT LVL 0
	OUT	INTA01,AL		; WRITE THE 8259 IMR
	MOV	AL,00010000B		; SEL TIM 0, LSB, MODE 0, BINARY
	OUT	TIM_CTL,AL		; WRITE TIMER CONTROL MODE REG
	MOV	CX,16H			; SET PGM LOOP CNT
	MOV	AL,CL			; SET TIMER 0 CNT REG
	OUT	TIMER0,AL		; WRITE TIMER 0 CNT REG
D8:
	TEST	DATA_AREA[@INTR_FLAG-DATA40],01H
					; DID TIMER 0 INTERRUPT OCCUR?
	JNZ	D9			; YES - CHECK TIMER OP FOR SLOW TIME
	LOOP	D8			; WAIT FOR INTR FOR SPECIFIED TIME
	JMP	D6			; TIMER 0 INTR DIDN'T OCCUR - ERR
D9:
	MOV	CL,12			; SET PGM LOOP CNT
	MOV	AL,0FFH 		; WRITE TIMER 0 CNT REG
	OUT	TIMER0,AL
	MOV	DATA_AREA[@INTR_FLAG-DATA40],0	; RESET INTR RECEIVED FLAG
	MOV	AL,0FEH 		; REENABLE TIMER 0 INTERRUPTS
	OUT	INTA01,AL
D10:
	TEST	DATA_AREA[@INTR_FLAG-DATA40],01H     ; DID TIMER 0 INTERRUPT OCCUR?
	JNZ	D6			; YES - TIMER CNTING TOO FAST, ERR
	LOOP	D10			; WAIT FOR INTR FOR SPECIFIED TIME

;----- SETUP TIMER 0 TO MODE 3

	MOV	AL,0FFH 		; DISABLE ALL DEVICE INTERRUPTS
	OUT	INTA01,AL
	MOV	AL,36H			; SEL TIM 0,LSB,MSB,MODE 3
	OUT	TIMER+3,AL		; WRITE TIMER MODE PEG
	MOV	AL,0
	OUT	TIMER,AL		; WRITE LSB TO TIMER 0 REG
	OUT	TIMER,AL		; WRITE MSB TO TIMER 0 REG
;------------------------------------------------
;	KEYBOARD TEST				:
;DESCRIPTION					:
;	RESET THE KEYBOARD AND CHECK THAT SCAN	:
;	CODE 'AA' IS RETURNED TO THE CPU.       :
;	CHECK FOR STUCK KEYS			:
;------------------------------------------------
TST12:
	MOV	AL,99H			; SET 8255 MODE A,C=IN B=OUT
	OUT	CMD_PORT,AL
	MOV	AL,DATA_AREA[@EQUIP_FLAG-DATA40]
	AND	AL,01			; TEST CHAMBER?
	JZ	F7			; BYPASS IF SO
	CMP	DATA_AREA[@MFG_TST-DATA40],1	; MANUFACTURING TEST MODE?
	JE	F7			; YES - SKIP KEYBOARD TEST
	CALL	KBD_RESET		; ISSUE RESET TO KEYBRD
	JCXZ	F6			; PRINT ERR MSG IF NO INTERRUPT
	MOV	AL,49H			; ENABLE KEYBOARD
	OUT	PORT_B,AL
	CMP	BL,0AAH 		; SCAN CODE AS EXPECTED?
	JNE	F6			; NO - DISPLAY ERROR MSG

;----- CHECK FOR STUCK KEYS

	MOV	AL,0C8H 		; CLR KBD, SET CLK LINE HIGH
	OUT	PORT_B,AL
	MOV	AL,48H			; ENABLE KBD,CLK IN NEXT BYTE
	OUT	PORT_B,AL
	SUB	CX,CX
F5:					; KBD_WAIT:
	LOOP	F5			; DELAY FOR A WHILE
	IN	AL,KB_DATA		; CHECK FOR STUCK KEYS
	CMP	AL,0			; SCAN CODE = 0?
	JE	F7			; YES - CONTINUE TESTING
	CALL	XPC_BYTE		; CONVERT AND PRINT
F6:
	MOV	SI,OFFSET F1		; GET MSG ADDR
	CALL	E_MSG			; PRINT MSG ON SCREEN
;------------------------------------------------
;	SETUP HARDWARE INT. VECTOR TABLE	:
;------------------------------------------------
F7:
	PUSH	DS			; SETUP_INT_TABLE:
	SUB	AX,AX
	MOV	ES,AX
	MOV	CX,08			; GET VECTOR CNT
	PUSH	CS			; SETUP DS SEG REG
	POP	DS
	MOV	SI,OFFSET VECTOR_TABLE
	MOV	DI,OFFSET @INT_PTR
F7A:
	MOVSW
	INC	DI			; SKIP OVER SEGMENT
	INC	DI
	LOOP	F7A
	POP	DS

;----- SET UP OTHER INTERRUPTS AS NECESSARY

	MOV	WORD PTR @NMI_PTR,OFFSET NMI_INT ; NMI INTERRUPT
	MOV	WORD PTR @INT5_PTR,OFFSET PRINT_SCREEN_1 ; PRINT SCREEN
	MOV	WORD PTR @BASIC_PTR+2,0F600H	 ; SEGMENT FOR CASSETTE BASIC

;----- SETUP TIMER 0 TO BLINK LED IF MANUFACTURING TEST MODE

	CMP	DATA_AREA[@MFG_TST-DATA40],01H	; MFG. TEST MODE?
	JNZ	EXP_IO
	MOV	WORD PTR DS:[1CH*4],OFFSET BLINK_INT  ; SETUP TIMER TO BLINK LED
	MOV	AL,0FEH 		; ENABLE TIMER INTERRUPT
	OUT	INTA01,AL
;----------------------------------------------------------------
; EXPANSION I/O BOX TEST					:
;	CHECK TO SEE IF EXPANSION BOX PRESENT - IF INSTALLED,	:
;	TEST DATA AND ADDRESS BUSES TO I/O BOX			:
;  ERROR='1801'                                                 :
;----------------------------------------------------------------

;----- DETERMINE IF BOX IS PRESENT

EXP_IO: 				; (CARD WAS ENABLED EARLIER)
	MOV	DX,0210H		; CONTROL PORT ADDRESS
	MOV	AX,5555H		; SET DATA PATTERN
	OUT	DX,AL
	MOV	AL,0FH
	IN	AL,DX			; RECOVER DATA
	CMP	AL,AH			; REPLY?
	JNE	E19			; NO RESPONSE. GO TO NEXT TEST
	NOT	AX			; MAKE DATA=AAAA
	OUT	DX,AL
	MOV	AL,0FH
	IN	AL,DX			; RECOVER DATA
	CMP	AL,AH
	JNE	E19			; NO ANSWER=NEXT TEST

;----- CHECK ADDRESS BUS

EXP2:
	MOV	BX,0001H
	MOV	DX,0215H		; LOAD HI. ADDR REG ADDRESS
	MOV	CX,0016 		; GO ACROSS 16 BITS
EXP3:
	MOV	CS:[BX],AL		; WRITE ADDRESS F0000+BX
	NOP
	IN	AL,DX			; READ ADDR. HIGH
	CMP	AL,BH
	JNE	EXP_ERR 		; GO ERROR IF MISCOMPARE
	INC	DX			; DX-216H (ADDR. LOW REG)
	IN	AL,DX
	CMP	AL,BL			; COMPARE TO LOW ADDRESS
	JNE	EXP_ERR
	DEC	DX			; DX BACK TO 215H
	SHL	BX,1
	LOOP	EXP3			; LOOP TILL '1' WALKS ACROSS BX

;----- CHECK DATA BUS

	MOV	CX,0008 		; DO 8 TIMES
	MOV	AL,01
	DEC	DX			; MAKE DX=214H (DATA BUS REG)
EXP4:
	MOV	AH,AL			; SAVE DATA BUS VALUE
	OUT	DX,AL			; SEND VALUE TO REG
	MOV	AL,01H
	IN	AL,DX			; RETRIVE VALUE FROM REG
	CMP	AL,AH			; = TO SAVED VALUE
	JNE	SHORT EXP_ERR
	SHL	AL,1			; FORM NEW DATA PATTERN
	LOOP	EXP4			; LOOP TILL BIT WALKS ACROSS AL
	JMP	SHORT E19		; GO ON TO NEXT TEST
EXP_ERR:
	MOV	SI,OFFSET F3C
	CALL	E_MSG
;--------------------------------------------------------
;	ADDITIONAL READ/WRITE STORAGE TEST		:
;DESCRIPTION						:
;	WRITE/READ DATA PATTERNS TO ANY READ/WRITE	:
;	STORAGE AFTER THE FIRST 32K.  STORAGE		:
;	ADDRESSABILITY IS CHECKED.			:
;--------------------------------------------------------
	ASSUME	DS:DATA
E19:
	CALL	DDS
	PUSH	DS
E20:
	CMP	@RESET_FLAG,1234H	; WARM START?
	JNE	E20A			; CONTINUE TEST IF NOT
	JMP	ROM_SCAN		; GO TO NEXT ROUTINE IF SO
E20A:
	MOV	AX,64			; STARTING AMT. OF MEMORY OK
	CALL	PRT_SIZ
	MOV	SI,@MEMORY_SIZE 	; GET MEM. SIZE WORD
	MOV	CL,6
	SHL	SI,CL
	XOR	DI,DI
	MOV	AX,0C00H
E20B:
	MOV	DS,AX			; SET SEG. REG
	MOV	WORD PTR [DI],055AAH
	MOV	WORD PTR [DI+2],AX
	ADD	AX,0400H		; POINT TO NEXT 16K
	CMP	AX,SI
	JB	E20B
	MOV	BX,0C00H
	MOV	AX,48
E21:
	MOV	DS,BX			; SET SEG. REG
	MOV	ES,BX
	PUSH	SI
	PUSH	BX
	PUSH	AX
	XOR	DI,DI
	XOR	AL,AL
	CMP	WORD PTR [DI],055AAH
	JNZ	E21A
	CMP	WORD PTR [DI+2],BX
	JNZ	E21A
	MOV	CX,2000H		; SET COUNT FOR 8K WORDS
	CALL	STGTST_CNT
	JNZ	E21A			; GO PRINT ERROR
	POP	AX			; RECOVER TESTED MEM NUMBER
	ADD	AX,16
	CALL	PRT_SIZ
	POP	BX			; RESTORE REGS
	POP	SI
	ADD	BX,0400H		; POINT TO NEXT 16K
	CMP	BX,SI
	JB	E21
	MOV	AL,10
	CALL	PRT_HEX 		; LINE FEED

;----- DMA TC0 SHOULD BE ON BY NOW - SEE IF IT IS

	IN	AL,DMA+08H
	AND	AL,00000001B		; TC0 STATUS BIT ON?
	JNZ	ROM_SCAN		; GO ON WITH NEXT TEST IF OK
	POP	DS
	MOV	@MFG_ERR_FLAG,03H	; <><><><><><><><><><><><><>
	JMP	D6			; POST 101 ERROR MSG AND HALT

;----- PRINT FAILING ADDRESS AND XOR'ED PATTERN IF DATA COMPARE ERROR

E21A:	MOV	CH,AL			; SAVE FAILING BIT PATTERN
	MOV	AL,13			; CARRAGE RETURN
	CALL	PRT_HEX
	MOV	AL,10
	CALL	PRT_HEX
	POP	AX			; RECOVER AMT. OF GOOD MEMORY
	POP	BX
	POP	SI
	MOV	DX,DS			; GET FAILING SEGMENT
	POP	DS
	PUSH	DS
	MOV	@MEMORY_SIZE,AX 	; LOAD MEM. SIZE WORD TO SHOW
					; HOW MUCH MEM. WORKING
	MOV	@MFG_ERR_FLAG,DH	; <><><><><><><><><><><><><>
					; <><>CHECKPOINTS 08->A0<><>
	CALL	PRT_SEG 		; PRINT IT
	MOV	AL,CH			; GET FAILING BIT PATTERN
	CALL	XPC_BYTE		; CONVERT AND PRINT CODE
	MOV	SI,OFFSET E1		; SETUP ADDRESS OF ERROR MSG
	CALL	E_MSG			; PRINT ERROR MSG
;----------------------------------------------------------------
; CHECK FOR OPTIONAL ROM FROM C8000->F4000 IN 2K BLOCKS 	:
;	(A VALID MODULE HAS '55AA' IN THE FIRST 2 LOCATIONS,    :
;	LENGTH INDICATOR (LENGTH/512) IN THE 3D LOCATION AND	:
;	TEST/INIT. CODE STARTING IN THE 4TH LOCATION.)		:
;----------------------------------------------------------------
ROM_SCAN:
	MOV	DX,0C800H		; SET BEGINNING ADDRESS
ROM_SCAN_1:
	MOV	DS,DX
	SUB	BX,BX			; SET BX=0000
	MOV	AX,[BX] 		; GET 1ST WORD FROM MODULE
	CLD
	CLD				; BUS SETTLING
	CMP	AX,0AA55H		; = TO ID WORD?
	JNZ	NEXT_ROM		; PROCEED TO NEXT ROM IF NOT
	CALL	ROM_CHECK		; GO CHECK OUT MODULE
	JMP	SHORT ARE_WE_DONE	; CHECK FOR END OF ROM SPACE
NEXT_ROM:
	ADD	DX,0080H		; POINT TO NEXT 2K ADDRESS
ARE_WE_DONE:
	CMP	DX,0F000H		; AT F0000 YET?
	JL	ROM_SCAN_1		; GO CHECK ANOTHER ADD. IF NOT
;----------------------------------------------------------------
;	DISKETTE ATTACHMENT TEST				:
;DESCRIPTION							:
;	CHECK IF IPL DISKETTE DRIVE IS ATTACHED TO SYSTEM.  IF	:
;	ATTACHED, VERIFY STATUS OF NEC FDC AFTER A RESET. ISSUE :
;	A RECAL AND SEEK CMD TO FDC AND CHECK STATUS. COMPLETE	:
;	SYSTEM INITIALIZATION THEN PASS CONTROL TO THE BOOT	:
;	LOADER PROGRAM. 					:
;----------------------------------------------------------------
F9:
	POP	DS
	MOV	AL,BYTE PTR @EQUIP_FLAG ; DISKETTE PRESENT?
	AND	AL,01H			; NO - BYPASS DISKETTE TEST
	JZ	F15
F10:					; DISK_TEST:
	MOV	DX,3F1H 		; I.D. PORT
	IN	AL,DX
	NOP
	MOV	BX,0FFFFH		; BUS PRECHARGE
	AND	AL,0F8H 		; KEEP I.D. BITS
	AND	@HF_CNTRL,11111110B	; RESET DUAL BIT
	CMP	AL,CARD_ID
	JNE	NO_ID
	OR	@HF_CNTRL,1		; SET DUAL BIT
NO_ID:
	IN	AL,INTA01
	AND	AL,0BFH 		; ENABLE DISKETTE INTERRUPTS
	OUT	INTA01,AL
	MOV	AH,0			; RESET NEC FDC
	MOV	DL,AH			; SET FOR DRIVE 0
	INT	13H			; VERIFY STATUS AFTER RESET
	TEST	AH,0FFH 		; STATUS OK?
	JNZ	F13			; NO - FDC FAILED

;----- TURN DRIVE 0 MOTOR ON

	MOV	DX,03F2H		; GET ADDR OF FDC CARD
	MOV	AL,1CH			; TURN MOTOR ON, EN DMA/INT
	OUT	DX,AL			; WRITE FDC CONTROL REG
	SUB	CX,CX
F11:					; MOTOR_WAIT:
	LOOP	F11			; WAIT FOR 1 SECOND
F12:					; MOTOR_WAIT1:
	LOOP	F12
	XOR	DX,DX			; SELECT DRIVE 0
	MOV	CH,34			; SELECT TRACK 34
	MOV	@SEEK_STATUS,DL
	CALL	SEEK			; RECALIBRATE DISKETTE AND SEEK TO 34
	JNC	F14			; OK--> GO TURN OFF MOTOR
F13:					; DISKETTE ERROR
	MOV	SI,OFFSET F3		; GET ADDR OF MSG
	JMP	SHORT F14A		; DISPLAY MESSAGE AFTER DISKETTE SETUP

;----- TURN DRIVE 0 MOTOR OFF

F14:					; SEQUENCE END ENTRY IF NO ERROR
	XOR	SI,SI			; ZERO SI IF NO ERROR
F14A:					; SEQUENCE END ENTRY IF ERROR
	MOV	AL,0CH			; TURN DRIVE 0 MOTOR OFF
	MOV	DX,03F2H		; FDC CTL ADDRESS
	OUT	DX,AL

;------SETUP DISKETTE STATES

	CALL DSKETTE_SETUP		; INITIALIZE DISKETTE PARMS
	JC	F14B			; CY-->DISKETTE SETUP ERROR
	OR	SI,SI			; PREVIOUS DISKETTE ERROR
	JZ	F15			; NZ-->DISKETTE ERROR BEFORE SETUP
F14B:
	MOV	SI,OFFSET F3		; GET ADDR OF MSG
	CALL	E_MSG			; GO PRINT ERROR MSG

;----- SETUP PRINTER AND RS232 BASE ADDRESSES IF DEVICE ATTACHED

F15:
	MOV	@INTR_FLAG,00H		; SET STRAY INTERRUPT FLAG = 00
	MOV	SI,OFFSET @KB_BUFFER	; SETUP KEYBOARD PARAMETERS
	MOV	@BUFFER_HEAD,SI
	MOV	@BUFFER_TAIL,SI
	MOV	@BUFFER_START,SI
	ADD	SI,32			;DEFAULT BUFFER OF 32 BYTES
	MOV	@BUFFER_END,SI
	MOV	DI,OFFSET @PRINT_TIM_OUT ;SET DEFAULT PRINTER TIMEOUT
	PUSH	DS
	POP	ES
	MOV	AX,1414H		; DEFAULT=20
	STOSW
	STOSW
	MOV	AX,0101H		;RS232 DEFAULT=01
	STOSW
	STOSW
	IN	AL,INTA01
	AND	AL,0FCH 		; ENABLE TIMER AND KBD INTS
	OUT	INTA01,AL

	CMP	BP,0000 		; CHECK FOR BP= NON-ZERO
					; (ERROR HAPPENED)
	JE	F15A_0			; CONTINUE IF NO ERROR
	MOV	DX,2			; 2 SHORT BEEPS (ERROR)
	CALL	ERR_BEEP
	MOV	SI,OFFSET F3D		; LOAD ERROR MSG
	CALL	P_MSG
ERR_WAIT:
	MOV	AH,00
	INT	16H			; WAIT FOR 'F1' KEY
	CMP	AH,3BH
	JNE	ERR_WAIT
	JMP	SHORT F15A		; BYPASS ERROR
F15A_0:
	CMP	@MFG_TST,1		; MFG MODE
	JE	F15A			; BYPASS BEEP
	MOV	DX,1			; 1 SHORT BEEP (NO ERRORS)
	CALL	ERR_BEEP
F15A:	MOV	AL,BYTE PTR @EQUIP_FLAG ; GET SWITCHES
	AND	AL,00000001B		; 'LOOP POST' SWITCH ON
	JNZ	F15B			; CONTINUE WITH BRING-UP
	JMP	START
F15B:	SUB	AH,AH
	MOV	AL,@CRT_MODE
	INT	10H			; CLEAR SCREEN
F15C:
	MOV	BP,OFFSET F4		; PRT_SRC_TBL
	MOV	SI,0
F16:					; PRT_BASE:
	MOV	DX,CS:[BP]		; GET PRINTER BASE ADDR
	MOV	AL,0AAH 		; WRITE DATA TO PORT A
	OUT	DX,AL
	PUSH	DS			; BUS SETTLEING
	IN	AL,DX			; READ PORT A
	POP	DS
	CMP	AL,0AAH 		; DATA PATTERN SAME
	JNE	F17			; NO - CHECK NEXT PRT CD
	MOV	[@PRINTER_BASE-DATA40][SI],DX	; YES - STORE PRT BASE ADDR
	INC	SI			; INCREMENT TO NEXT WORD
	INC	SI
F17:
	INC	BP			; POINT TO NEXT BASE ADDR
	INC	BP
	CMP	BP,OFFSET F4E		; ALL POSSIBLE ADDRS CHECKED?
	JNE	F16			; PRT_BASE
	MOV	BX,0			; POINTER TO RS232 TABLE
	MOV	DX,3FAH 		; CHECK IF RS232 CD 1 ATTCH?
	IN	AL,DX			; READ INTR ID REG
	TEST	AL,0F8H
	JNZ	F18
	MOV	[@RS232_BASE-DATA40][BX],3F8H	; SETUP RS232 CD #1 ADDR
	INC	BX
	INC	BX
F18:
	MOV	DX,2FAH 		; CHECK IF RS232 CD 2 ATTCH
	IN	AL,DX			; READ INTERRUPT ID REG
	TEST	AL,0F8H
	JNZ	F19			; BASE_END
	MOV	[@RS232_BASE-DATA40][BX],2F8H	; SETUP RS232 CD #2
	INC	BX
	INC	BX

;----- SET UP EQUIP FLAG TO INDICATE NUMBER OF PRINTERS AND RS232 CARDS

F19:					; BASE_END:
	MOV	AX,SI			; SI HAS 2* NUMBER OF RS232
	MOV	CL,3			; SHIFT COUNT
	ROR	AL,CL			; ROTATE RIGHT 3 POSITIONS
	OR	AL,BL			; OR IN THE PRINTER COUNT
	MOV	BYTE PTR @EQUIP_FLAG+1,AL	; STORE AS SECOND BYTE
	MOV	DX,201H
	IN	AL,DX
	NOP
	NOP
	NOP
	TEST	AL,0FH
	JNZ	F20			; NO_GAME_CARD
	OR	BYTE PTR @EQUIP_FLAG+1,16
F20:					; NO_GAME_CARD:

;----- ENABLE NMI INTERRUPTS

	IN	AL,PORT_B		; RESET CHECK ENABLES
	OR	AL,30H
	OUT	PORT_B,AL
	AND	AL,0CFH
	OUT	PORT_B,AL
	MOV	AL,80H			; ENABLE NMI INTERRUPTS
	OUT	0A0H,AL
F21:					; LOAD_BOOT_STRAP:
	INT	19H			; GO TO THE BOOT LOADER

;--- INT 19 ---------------------------------------------
; BOOT STRAP LOADER					:
;	TRACK 0, SECTOR 1 IS READ INTO THE		:
;	BOOT LOCATION (SEGMENT 0, OFFSET 7C00)		:
;	AND CONTROL IS TRANSFERRED THERE.		:
;							:
;	IF THERE IS A HARDWARE ERROR CONTROL IS 	:
;	TRANSFERRED TO THE ROM BASIC ENTRY POINT.	:
;--------------------------------------------------------
	ASSUME	CS:CODE,DS:ABS0
;	ORG	0E6F2H
	ORG	006F2H

BOOT_STRAP	PROC	NEAR
	STI				; ENABLE INTERRUPTS
	SUB	AX,AX			; ESTABLISH ADDRESSING
	MOV	DS,AX

;----- RESET DISKETTE PARAMETER TABLE VECTOR

	MOV	WORD PTR @DISK_POINTER,OFFSET DISK_BASE
	MOV	WORD PTR @DISK_POINTER+2,CS

;----- LOAD SYSTEM FROM DISKETTE -- CX HAS RETRY COUNT

	MOV	CX,4			; SET RETRY COUNT
H1:					; IPL_SYSTEM
	PUSH	CX			; SAVE RETRY COUNT
	MOV	AH,0			; RESET THE DISKETTE SYSTEM
	INT	13H			; DISKETTE_IO
	JC	H2			; IF ERROR, TRY AGAIN
	MOV	AX,201H 		; READ IN THE SINGLE SECTOR
	SUB	DX,DX
	MOV	ES,DX
	MOV	BX,OFFSET @BOOT_LOCN
					; DRIVE 0, HEAD 0
	MOV	CX,1			; SECTOR 1, TRACK 0
	INT	13H			; DISKETTE_IO
H2:
	POP	CX			; RECOVER RETRY COUNT
	JNC	H4			; CF SET BY UNSUCCESSFUL READ
	LOOP	H1			; DO IT FOR RETRY TIMES

;------ UNABLE TO IPL FROM THE DISKETTE

H3:
	INT	18H			; GO TO RESIDENT BASIC

;----- IPL WAS SUCCESSFUL

H4:
	JMP	@BOOT_LOCN
BOOT_STRAP	ENDP

;;-	ORG	0E729H
	ORG	00729H
A1	DW	1047			; 110 BAUD	; TABLE OF VALUES
	DW	768			; 150		; FOR INITIALIZATION
	DW	384			; 300
	DW	192			; 600
	DW	96			; 1200
	DW	48			; 2400
	DW	24			; 4800
	DW	12			; 9600

RS232_IO:
	JMP	RS232_IO_1
					;	USE INT 15 H  AH= 0C0H
CONF_TBL:				; CONFIGURATION TABLE FOR THIS SYSTEM
	DW	CONF_E-CONF_TBL-2	; LENGTH OF FOLLOWING TABLE
	DB	MODEL_BYTE		; SYSTEM MODEL BYTE
	DB	SUB_MODEL_BYTE		; SYSTEM SUB MODEL TYPE BYTE
	DB	BIOS_LEVEL		; BIOS REVISION LEVEL
	DB	10010000B		; 10000000 = DMA CHANNEL 3 USE BY BIOS
					; 01000000 = CASCADED INTERRUPT LEVEL 2
					; 00100000 = REAL TIME CLOCK AVAILABLE
					; 00010000 = KEYBOARD SCAN CODE HOOK 1AH
	DB	0			; RESERVED
	DB	0			; RESERVED
	DB	0			; RESERVED
	DB	0			; RESERVED
CONF_E	EQU	$			; RESERVED FOR EXPANSION

;------------------------------------------------------------------------
;	PRINT ADDRESS AND ERROR MESSAGE FOR ROM CHECKSUM ERRORS 	:
;------------------------------------------------------------------------
ROM_ERR PROC	NEAR
	PUSH	DX			; SAVE POINTER
	PUSH	AX
	MOV	DX,DS			; GET ADDRESS POINTER
	MOV	ES:@MFG_ERR_FLAG,DH	; <><><><><><><><><><><><><><><>
					; <><><>CHECKPOINTS C0->F4<><><>
	CMP	DX,0C800H		; CRT CARD IN ERROR?
	JL	ROM_ERR_BEEP		; GIVE CRT CARD FAIL BEEP
	CALL	PRT_SEG 		; PRINT SEGEMENT IN ERROR
	MOV	SI,OFFSET F3A		; DISPLAY ERROR MSG
	CALL	E_MSG
ROM_ERR_END:
	POP	AX
	POP	DX
	RET
ROM_ERR_BEEP:
	MOV	DX,0102H		; BEEP 1 LONG, 2 SHORT
	CALL	ERR_BEEP
	JMP	SHORT ROM_ERR_END
ROM_ERR ENDP

F3D	DB	'ERROR. (RESUME = "F1" KEY)',13,10      ; ERROR PROMPT

PRT_SIZ PROC	NEAR
	PUSH	AX
	MOV	BX,10			; SET UP FOR DECIMAL CONVERT
	MOV	CX,3			; OF 3 NIBBLES
DECIMAL_LOOP:
	XOR	DX,DX
	DIV	BX			; DIVIDE BY 10
	OR	DL,30H			; MAKE INTO ASCII
	PUSH	DX			; SAVE
	LOOP	DECIMAL_LOOP
	MOV	CX,3
PRT_DEC_LOOP:
	POP	AX			; RECOVER A NUMBER
	CALL	PRT_HEX
	LOOP	PRT_DEC_LOOP
	MOV	CX,7
	MOV	SI,OFFSET F3B		; PRINT ' KB OK'
KB_LOOP:
	MOV	AL,CS:[SI]
	INC	SI
	CALL	PRT_HEX
	LOOP	KB_LOOP
	POP	AX			; RECOVER WORK REGS
	RET
PRT_SIZ ENDP

;	ORG	0E82EH
	ORG	0082EH
KEYBOARD_IO:
	JMP	KEYBOARD_IO_1

;	ORG	0E987H
	ORG	00987H
KB_INT:
	JMP	KB_INT_1

F1	DB	' 301',13,10            ; KEYBOARD ERROR
F3	DB	'601',13,10             ; DISKETTE ERROR

;--- INT  1A H -- SYSTEM AND REAL TIME CLOCK SERVICES --------------------------
;									       :
;	THIS BIOS ROUTINE ALLOWS THE CLOCKS TO BE SET OR READ		       :
;									       :
; PARAMETERS:								       :
;     (AH) = 00H  READ THE CURRENT CLOCK SETTING AND RETURN WITH,	       :
;		       (CX) = HIGH PORTION OF COUNT			       :
;		       (DX) = LOW PORTION OF COUNT			       :
;		       (AL) = 0 TIMER HAS NOT PASSED 24 HOURS SINCE LAST READ  :
;			      1 IF ON ANOTHER DAY. (RESET TO ZERO AFTER READ)  :
;									       :
;     (AH) = 01H  SET THE CURRENT CLOCK USING,				       :
;		      (CX) = HIGH PORTION OF COUNT			       :
;		      (DX) = LOW PORTION OF COUNT.			       :
;									       :
;		NOTE: COUNTS OCCUR AT THE RATE OF 1193180/65536 COUNTS/SECOND  :
;			     (OR ABOUT 18.2 PER SECOND -- SEE EQUATES)	       :
;									       :
;     (AH) = 0AH  READ THE CURRENT COUNT OF DAYS AND RETURN WITH,	       :
;		       (CX) = COUNT OF ELAPSED DAYS			       :
;									       :
;     (AH) = 0BH  SET THE CURRENT COUNT OF DAYS USING,			       :
;		      (CX) = COUNT OF ELAPSED DAYS			       :
;									       :
; NOTES: FOR ALL RETURNS CY= 0 FOR SUCCESSFUL OPERATION.		       :
;	 INTERRUPTS ARE DISABLED DURING DATA MODIFICATION.		       :
;	 AH & AL ARE RETURNED MODIFIED AND NOT DEFINED EXCEPT WHERE INDICATED. :
;-------------------------------------------------------------------------------
	ASSUME	CS:CODE,DS:DATA

TIME_OF_DAY_1	PROC	FAR
TIME_OF_DAY_11:
	STI				; INTERRUPTS BACK ON
	CMP	AH,(RTC_TBE-RTC_TB)/2	; CHECK IF COMMAND IN VALID RANGE
	CMC				; COMPLEMENT CARRY FOR ERROR EXIT
	JC	TIME_9			; EXIT WITH CARRY = 1 IF NOT VALID

	PUSH	DS			; SAVE USERS (DS) SEGMENT
	CALL	DDS			; GET DATA SEGMENT SELECTOR
	PUSH	SI			; SAVE WORK REGISTER
	MOV	AL,AH			; MOVE FUNCTION TO (AL) REGISTER
	CBW				; CONVERT FUNCTION TO BYTE OFFSET
	ADD	AX,AX			; CONVERT FUNCTION TO WORD OFFSET (CY=0)
	MOV	SI,AX			; PLACE INTO ADDRESSING REGISTER
	CLI				; NO INTERRUPTS DURING TIME FUNCTIONS
	CALL	CS:[SI]+OFFSET RTC_TB	; VECTOR TO FUNCTION REQUESTED WITH CY=0
					;  RETURN WITH CARRY FLAG SET FOR RESULT
	STI				; INTERRUPTS BACK ON
	MOV	AH,0			; CLEAR (AH) TO ZERO
	POP	SI			; RECOVER USERS REGISTER
	POP	DS			; RECOVER USERS SEGMENT SELECTOR
TIME_9: 				; RETURN WITH CY= 0 IF NO ERROR
	RET	2
					;	ROUTINE VECTOR TABLE (AH)=
RTC_TB	DW	RTC_00			; 00H = READ CURRENT CLOCK COUNT
	DW	RTC_10			; 01H = SET CLOCK COUNT
	DW	RTC_NS			; 02H	 INVALID
	DW	RTC_NS			; 03H	 INVALID
	DW	RTC_NS			; 04H	 INVALID
	DW	RTC_NS			; 05H	 INVALID
	DW	RTC_NS			; 06H	 INVALID
	DW	RTC_NS			; 07H	 INVALID
	DW	RTC_NS			; 08H	 INVALID
	DW	RTC_NS			; 09H	 INVALID
	DW	RTC_A0			; 0AH = READ SYSTEM DAY COUNTER
	DW	RTC_B0			; 0BH = WRITE SYSTEM DAY COUNTER
RTC_TBE EQU	$

TIME_OF_DAY_1	ENDP

RTC_00	PROC	NEAR			;	READ TIME COUNT
	MOV	AL,@TIMER_OFL		; GET THE OVERFLOW FLAG
	MOV	@TIMER_OFL,0		; AND THEN RESET THE OVERFLOW FLAG
	MOV	CX,@TIMER_HIGH		; GET COUNT OF TIME HIGH WORD
	MOV	DX,@TIMER_LOW		; GET COUNT OF TIME LOW WORD
	RET				; RETURN WITH NO CARRY

RTC_10: 				;	SET TIME COUNT
	MOV	@TIMER_LOW,DX		; SET TIME COUNT LOW WORD
	MOV	@TIMER_HIGH,CX		; SET THE TIME COUNT HIGH WORD
	MOV	@TIMER_OFL,0		; RESET OVERFLOW FLAG
	RET				; RETURN WITH NO CARRY

RTC_NS: 				;      INVALID FUNCTION (NOT SUPPORTED)
	STC				; SET CARRY FLAG FOR ERROR (CY=1)
	RET				; EXIT THROUGH COMMON RETURN

RTC_A0:
	MOV	CX,@DAY_COUNT		; GET COUNT OF DAYS
	RET				; EXIT THROUGH COMMON RETURN WITH CY=0

RTC_B0:
	MOV	@DAY_COUNT,CX		; SET COUNT OF DAYS
	RET				; EXIT THROUGH COMMON RETURN WITH CY=0

RTC_00	ENDP

;	ORG	0EC59H
	ORG	00C59H
DISKETTE_IO:	JMP	DISKETTE_IO_1

;--- BEEP ---------------------------------------------------------------
;	ROUTINE TO SOUND THE BEEPER USING TIMER 2 FOR TONE		:
; ENTRY:								:
;	(BL) = DURATION COUNTER ( 1 FOR 1/64 SECOND )			:
;	(CX) = FREQUENCY DIVISOR (1193180/FREQUENCY) (1331 FOR 886 HZ)	:
; EXIT: 								:
;	(AX),(BL),(CX) MODIFIED.					:
;------------------------------------------------------------------------

BEEP	PROC	NEAR			;	SETUP TIMER 2
	PUSHF				; SAVE INTERRUPT STATUS
	CLI				; BLOCK INTERRUPTS DURING UPDATE
	MOV	AL,10110110B		; SELECT TIMER 2,LSB,MSB,BINARY
	OUT	TIMER+3,AL		; WRITE THE TIMER MODE REGISTER
	NOP				; I/O DELAY
	MOV	AL,CL			; DIVISOR FOR HZ (LOW)
	OUT	TIMER+2,AL		; WRITE TIMER 2 COUNT - LSB
	NOP				; I/O DELAY
	MOV	AL,CH			; DIVISOR FOR HZ (HIGH)
	OUT	TIMER+2,AL		; WRITE TIMER 2 COUNT - MSB
	IN	AL,PORT_B		; GET CURRENT SETTING OF PORT
	MOV	AH,AL			; SAVE THAT SETTING
	OR	AL,GATE2+SPK2		; GATE TIMER 2 AND TURN SPEAKER ON
	OUT	PORT_B,AL		; AND RESTORE INTERRUPT STATUS
	POPF
G7:					;	1/64 SECOND PER COUNT (BL)
	MOV	CX,1035 		; DELAY COUNT FOR 1/64 OF A SECOND
	CALL	WAITF			; GO TO BEEP DELAY 1/64 COUNT
	DEC	BL			; (BL) LENGTH COUNT EXPIRED?
	JNZ	G7			; NO - CONTINUE BEEPING SPEAKER

	PUSHF				; SAVE INTERRUPT STATUS
	CLI				; BLOCK INTERRUPTS DURING UPDATE
	IN	AL,PORT_B		; GET CURRENT PORT VALUE
	OR	AL,NOT (GATE2+SPK2)	; ISOLATE CURRENT SPEAKER BITS N CASE
	AND	AH,AL			;  SOMEONE TURNED THEM OFF DURING BEEP
	MOV	AL,AH			; RECOVER VALUE OF PORT
	AND	AL,NOT (GATE2+SPK2)	; FORCE SPEAKER DATA OFF
	OUT	PORT_B,AL		; AND STOP SPEAKER TIMER
	POPF				; RESTORE INTERRUPT FLAG STATE
	MOV	CX,1035 		; FORCE 1/64 SECOND DELAY (SHORT)
	CALL	WAITF			; MINIMUM DELAY BETWEEN ALL BEEPS
	PUSHF				; SAVE INTERRUPT STATUS
	CLI				; BLOCK INTERRUPTS DURING UPDATE
	IN	AL,PORT_B		; GET CURRENT PORT VALUE IN CASE
	AND	AL,GATE2+SPK2		;  SOMEONE TURNED THEM ON
	OR	AL,AH			; RECOVER VALUE OF PORT_B
	OUT	PORT_B,AL		; RESTORE SPEAKER STATUS
	POPF				; RESTORE INTERRUPT FLAG STATE
	RET

BEEP	ENDP

;--- WAITF -------------------------------------------------------------
;	FIXED TIME WAIT ROUTINE HARDWARE CONTROLLED - NOT PROCESSOR)   :
;								       :
; ENTRY:							       :
;	(CX) = COUNT OF 15.085737 MICROSECOND INTERVALS TO WAIT        :
;		MEMORY REFRESH TIMER 1 OUTPUT AT THE DMA CHANNEL 0     :
;		ADDRESS REGISTER USED AS REFERENCE.		       :
; EXIT: 							       :
;		AFTER (CX) TIME COUNT (PLUS OR MINUS 31 MICROSECONDS)  :
;	(CX) = 0						       :
;-----------------------------------------------------------------------

WAITF	PROC	NEAR			;	DELAY FOR  (CX)*15.085737 US
	PUSH	AX			; SAVE WORK REGISTER (AH)
	SHR	CX,1			; DIVIDE 15us COUNT DOWN TO 30us COUNT
	ADC	CX,0
	JCXZ	WAITF9			; EXIT IF COUNT WAS ZERO OR ONE

	OUT	DMA+12,AL		; CLEAR THE DMA BYTE POINTER FLIP/FLOP
WAITF1:
	PUSHF				; SAVE INTERRUPT STATE
	CLI				; BLOCK INTERRUPTS TILL NEXT CHANGE
WAITF3: 				;  WAIT FOR REFRESH ADDRESS CHANGE
	IN	AL,DMA			; READ CURRENT ADDRESS LOW BYTE
	AND	AL,11111110B		; DISCARD LOW BIT (30us)
	CMP	AH,AL			; DID VALUE JUST CHANGE
	MOV	AH,AL			; SAVE NEW/OLD VALUE INCASE IT DID
	IN	AL,DMA			; READ HIGH BYTE (AND IGNORE)
	JE	WAITF3			; WAIT FOR A CHANGE IN ADDRESS BITS

	POPF				; RESTORE INTERRUPTS
	LOOP	WAITF1			; DECREMENT CYCLES COUNT TILL COUNT END
WAITF9:
	POP	AX			; RESTORE (AH)
	RET				; RETURN (CX)= 0

WAITF	ENDP

;---------------------------------------------------------------
;	PRINT A SEGMENT VALUE TO LOOK LIKE A 20 BIT ADDRESS	:
;	DX MUST CONTAIN SEGMENT VALUE TO BE PRINTED		:
;---------------------------------------------------------------
PRT_SEG PROC	NEAR
	MOV	AL,DH			; GET MSB
	CALL	XPC_BYTE
	MOV	AL,DL			; LSB
	CALL	XPC_BYTE
	MOV	AL,'0'                  ;  PRINT A '0 '
	CALL	PRT_HEX
	MOV	AL,' '                  ;SPACE
	CALL	PRT_HEX
	RET
PRT_SEG ENDP

;----------------------------------------------------------------
; THIS SUBROUTINE PERFORMS A READ/WRITE STORAGE TEST ON A BLOCK :
;	OF STORAGE.						:
; ENTRY REQUIREMENTS:						:
;	ES = ADDRESS OF STORAGE SEGMENT BEING TESTED		:
;	DS = ADDRESS OF STORAGE SEGMENT BEING TESTED		:
;	CX = WORD COUNT OF STORAGE BLOCK TO BE TESTED		:
; EXIT PARAMETERS:						:
;	ZERO FLAG = 0 IF STORAGE ERROR (DATA COMPARE OR PARITY	:
;	CHECK.	AL=0 DENOTES A PARITY CHECK. ELSE AL=XOR'ED     :
;	BIT PATTERN OF THE EXPECTED DATA PATTERN VS THE ACTUAL	:
;	DATA READ.						:
; AX,BX,CX,DX,DI, AND SI ARE ALL DESTROYED.			:
;----------------------------------------------------------------

STGTST_CNT	PROC	NEAR
	MOV	BX,CX			; SAVE WORD COUNT OF BLOCK TO TEST
	CLD				; SET DIR FLAG TO INCREMENT
	SUB	DI,DI			; SET DI=OFFSET 0 REL TO ES REG
	MOV	AH,0FFH
C2_1:
	MOV	[DI],AH 		; ON FIRST BYTE
	MOV	AL,[DI]
	XOR	AL,AH			; O.K.?
	JNZ	C7			; GO ERROR IF NOT
	DEC	AH
	JNZ	C2_1			; LOOP TILL WRAP THROUGH FF
	MOV	AX,055AAH		; GET INITIAL DATA PATTERN TO WRITE
	MOV	DX,AX			; SET INITIAL COMPARE PATTERN.
	REP	STOSW			; FILL STORAGE LOCATIONS IN BLOCK
	IN	AL,PORT_B
	OR	AL,030H 		; TOGGLE PARITY CHECK LATCHES
	OUT	PORT_B,AL
	NOP
	AND	AL,0CFH
	OUT	PORT_B,AL
;
	DEC	DI			; POINT TO LAST WORD JUST WRITTEN
	DEC	DI
	STD				; SET DIR FLAG TO GO BACKWARDS
	MOV	SI,DI			; INITIALIZE DESTINATION POINTER
	MOV	CX,BX			; SETUP WORD COUNT FOR LOOP
C3:					;	INNER TEST LOOP
	LODSW				; READ OLD TEST WORD FROM STORAGE
	XOR	AX,DX			; DATA READ AS EXPECTED ?
	JNE	C7X			; NO - GO TO ERROR ROUTINE
	MOV	AX,0AA55H		; GET NEXT DATA PATTERN TO WRITE
	STOSW				; WRITE INTO LOCATION JUST READ
	LOOP	C3			; DECREMENT WORD COUNT AND LOOP
;
	CLD				; SET DIR FLAG TO GO FORWARD
	INC	DI			; SET POINTER TO BEG LOCATION
	INC	DI
	MOV	SI,DI			; INITIALIZE DESTINATION POINTER
	MOV	CX,BX			; SETUP WORD COUNT FOR LOOP
	MOV	DX,AX			; SETUP COMPARE PATTERN OF "0AA55H".
C4:					;	INNER TEST LOOP
	LODSW				; READ OLD TEST WORD FROM STORAGE
	XOR	AX,DX			; DATA READ AS EXPECTED ?
	JNE	C7X			; NO - GO TO ERROR ROUTINE
	DEC	AX			; GET NEXT DATA PATTERN TO WRITE
	DEC	AX
	STOSW				; WRITE INTO LOCATION JUST READ
	LOOP	C4			; DECREMENT WORD COUNT AND LOOP
;
	DEC	DI			; POINT TO LAST WORD JUST WRITTEN
	DEC	DI
	STD				; SET DIR FLAG TO GO BACKWARDS
	MOV	SI,DI			; INITIALIZE DESTINATION POINTER
	MOV	CX,BX			; SETUP WORD COUNT FOR LOOP
	MOV	DX,AX			; SETUP COMPARE PATTERN "0FFFFH".
C5:					;	INNER TEST LOOP
	LODSW				; READ OLD TEST WORD FROM STORAGE
	XOR	AX,DX			; DATA READ AS EXPECTED ?
	JNE	C7X			; NO - GO TO ERROR ROUTINE
	MOV	AX,00201H		; GET NEXT DATA PATTERN TO WRITE
	STOSW				; WRITE INTO LOCATION JUST READ
	LOOP	C5			; DECREMENT WORD COUNT AND LOOP
;
	CLD				; SET DIR FLAG TO GO FORWARD
	INC	DI			; SET POINTER TO BEG LOCATION
	INC	DI
	MOV	SI,DI			; INITIALIZE DESTINATION POINTER
	MOV	CX,BX			; SETUP WORD COUNT FOR LOOP
	MOV	DX,AX			; SETUP COMPARE PATTERN OF "00101H".
C6:					;	INNER TEST LOOP
	LODSW				; READ OLD TEST WORD FROM STORAGE
	XOR	AX,DX			; DATA READ AS EXPECTED ?
	STOSW				; WRITE INTO LOCATION JUST READ
	LOOPE	C6			; DECREMENT WORD COUNT AND LOOP
	JNE	C7X			; NO - GO TO ERROR ROUTINE
;
	DEC	DI			; POINT TO LAST WORD JUST WRITTEN
	DEC	DI
	STD				; SET DIR FLAG TO GO BACKWARDS
	MOV	SI,DI			; INITIALIZE DESTINATION POINTER
	MOV	CX,BX			; SETUP WORD COUNT FOR LOOP
	MOV	DX,AX			; SETUP COMPARE PATTERN "00000H".
C6X:
	LODSW				; VERIFY MEMORY IS ZERO
	XOR	AX,DX			; DATA READ AS EXPECTED ?
	LOOPE	C6X			; DECREMENT WORD COUNT AND LOOP
	JNE	C7X			; NO - GO TO ERROR ROUTINE
;
	IN	AL,PORT_C		; DID A PARITY ERROR OCCUR ?
	AND	AL,0C0H 		; ZERO FLAG WILL BE OFF PARITY ERROR
	MOV	AL,000H 		; AL=0 DATA COMPARE OK
	JMP	C7
C7X:
	CMP	AL,0			; FIND BYTE THAT FAILED.
	JNZ	C7
	OR	AL,AH
C7:
	CLD				; SET DIRECTION FLAG TO INC
	RET
STGTST_CNT	ENDP

;	ORG	0EF57H
	ORG	00F57H
DISK_INT:	JMP	DISK_INT_1

;	ORG	0EF79H
	ORG	00F79H
;---------------------------------------------------------------------
;	MEDIA DRIVE/PARAMETER TABLES				     :
;---------------------------------------------------------------------
;---------------------------------------------------------------------
;	40 TRACK LOW DATA RATE MEDIA IN 40 TRACK LOW DATA RATE DRIVE :
;---------------------------------------------------------------------
MD_TBL1 	LABEL BYTE
	DB	11011111B	; SRT=D, HD UNLOAD=0F - 1ST SPECIFY BYTE
	DB	2		; HD LOAD=1, MODE=DMA - 2ND SPECIFY BYTE
	DB	MOTOR_WAIT	; WAIT TIME AFTER OPERATION TILL MOTOR OFF
	DB	2		; 512 BYTES/SECTOR
	DB	09		; EOT ( LAST SECTOR ON TRACK)
	DB	02AH		; GAP LENGTH
	DB	0FFH		; DTL
	DB	050H		; GAP LENGTH FOR FORMAT
	DB	0F6H		; FILL BYTE FOR FORMAT
	DB	15		; HEAD SETTLE TIME (MILLISECONDS)
	DB	8		; MOTOR START TIME (1/8 SECONDS)
	DB	39		; MAX. TRACK NUMBER
	DB	RATE_250	; DATA TRANSFER RATE
;---------------------------------------------------------------------
;	40 TRACK LOW DATA RATE MEDIA IN 80 TRACK HI DATA RATE DRIVE  :
;---------------------------------------------------------------------
MD_TBL2 	LABEL BYTE
	DB	11011111B	; SRT=D, HD UNLOAD=0F - 1ST SPECIFY BYTE
	DB	2		; HD LOAD=1, MODE=DMA - 2ND SPECIFY BYTE
	DB	MOTOR_WAIT	; WAIT TIME AFTER OPERATION TILL MOTOR OFF
	DB	2		; 512 BYTES/SECTOR
	DB	09		; EOT ( LAST SECTOR ON TRACK)
	DB	02AH		; GAP LENGTH
	DB	0FFH		; DTL
	DB	050H		; GAP LENGTH FOR FORMAT
	DB	0F6H		; FILL BYTE FOR FORMAT
	DB	15		; HEAD SETTLE TIME (MILLISECONDS)
	DB	8		; MOTOR START TIME (1/8 SECONDS)
	DB	39		; MAX. TRACK NUMBER
	DB	RATE_300	; DATA TRANSFER RATE
;---------------------------------------------------------------------
;	80 TRACK HI DATA RATE MEDIA IN 80 TRACK HI DATA RATE DRIVE   :
;---------------------------------------------------------------------
MD_TBL3 	LABEL BYTE
	DB	11011111B	; SRT=D, HD UNLOAD=0F - 1ST SPECIFY BYTE
	DB	2		; HD LOAD=1, MODE=DMA - 2ND SPECIFY BYTE
	DB	MOTOR_WAIT	; WAIT TIME AFTER OPERATION TILL MOTOR OFF
	DB	2		; 512 BYTES/SECTOR
	DB	15		; EOT ( LAST SECTOR ON TRACK)
	DB	01BH		; GAP LENGTH
	DB	0FFH		; DTL
	DB	054H		; GAP LENGTH FOR FORMAT
	DB	0F6H		; FILL BYTE FOR FORMAT
	DB	15		; HEAD SETTLE TIME (MILLISECONDS)
	DB	8		; MOTOR START TIME (1/8 SECONDS)
	DB	79		; MAX. TRACK NUMBER
	DB	RATE_500	; DATA TRANSFER RATE
;---------------------------------------------------------------------
;	80 TRACK LOW DATA RATE MEDIA IN 80 TRACK LOW DATA RATE DRIVE :
;---------------------------------------------------------------------
MD_TBL4 	LABEL BYTE
	DB	11011111B	; SRT=D, HD UNLOAD=0F - 1ST SPECIFY BYTE
	DB	2		; HD LOAD=1, MODE=DMA - 2ND SPECIFY BYTE
	DB	MOTOR_WAIT	; WAIT TIME AFTER OPERATION TILL MOTOR OFF
	DB	2		; 512 BYTES/SECTOR
	DB	09		; EOT ( LAST SECTOR ON TRACK)
	DB	02AH		; GAP LENGTH
	DB	0FFH		; DTL
	DB	050H		; GAP LENGTH FOR FORMAT
	DB	0F6H		; FILL BYTE FOR FORMAT
	DB	15		; HEAD SETTLE TIME (MILLISECONDS)
	DB	8		; MOTOR START TIME (1/8 SECONDS)
	DB	79		; MAX. TRACK NUMBER
	DB	RATE_250	; DATA TRANSFER RATE
;---------------------------------------------------------------------
;	80 TRACK LOW DATA RATE MEDIA IN 80 TRACK HI DATA RATE DRIVE  :
;---------------------------------------------------------------------
MD_TBL5 	LABEL BYTE
	DB	11011111B	; SRT=D, HD UNLOAD=0F - 1ST SPECIFY BYTE
	DB	2		; HD LOAD=1, MODE=DMA - 2ND SPECIFY BYTE
	DB	MOTOR_WAIT	; WAIT TIME AFTER OPERATION TILL MOTOR OFF
	DB	2		; 512 BYTES/SECTOR
	DB	09		; EOT ( LAST SECTOR ON TRACK)
	DB	02AH		; GAP LENGTH
	DB	0FFH		; DTL
	DB	050H		; GAP LENGTH FOR FORMAT
	DB	0F6H		; FILL BYTE FOR FORMAT
	DB	15		; HEAD SETTLE TIME (MILLISECONDS)
	DB	8		; MOTOR START TIME (1/8 SECONDS)
	DB	79		; MAX. TRACK NUMBER
	DB	RATE_250	; DATA TRANSFER RATE
;---------------------------------------------------------------------
;	80 TRACK HI DATA RATE MEDIA IN 80 TRACK HI DATA RATE DRIVE   :
;---------------------------------------------------------------------
MD_TBL6 	LABEL BYTE
	DB	10101111B	; SRT=A, HD UNLOAD=0F - 1ST SPECIFY BYTE
	DB	2		; HD LOAD=1, MODE=DMA - 2ND SPECIFY BYTE
	DB	MOTOR_WAIT	; WAIT TIME AFTER OPERATION TILL MOTOR OFF
	DB	2		; 512 BYTES/SECTOR
	DB	18		; EOT ( LAST SECTOR ON TRACK)
	DB	01BH		; GAP LENGTH
	DB	0FFH		; DTL
	DB	06CH		; GAP LENGTH FOR FORMAT
	DB	0F6H		; FILL BYTE FOR FORMAT
	DB	15		; HEAD SETTLE TIME (MILLISECONDS)
	DB	8		; MOTOR START TIME (1/8 SECONDS)
	DB	79		; MAX. TRACK NUMBER
	DB	RATE_500	; DATA TRANSFER RATE
;------------------------------------------------------------------------
; DISK_BASE								:
;	THIS IS THE SET OF PARAMETERS REQUIRED FOR DISKETTE OPERATION.	:
;	THEY ARE POINTED AT BY THE DATA VARIABLE DISK_POINTER. TO	:
;	MODIFY THE PARAMETERS, BUILD ANOTHER PARAMETER BLOCK AND POINT	:
;	AT IT								:
;------------------------------------------------------------------------
;	ORG	0EFC7H
	ORG	00FC7H
DISK_BASE	LABEL	BYTE
	DB	11001111B	; SRT=C, HD UNLOAD=0F - 1ST SPECIFY BYTE
	DB	2		; HD LOAD=1, MODE=DMA - 2ND SPECIFY BYTE
	DB	MOTOR_WAIT	; WAIT TIME AFTER OPERATION TILL MOTOR OFF
	DB	2		; 512 BYTES/SECTOR
	DB	8		; EOT ( LAST SECTOR ON TRACK)
	DB	02AH		; GAP LENGTH
	DB	0FFH		; DTL
	DB	050H		; GAP LENGTH FOR FORMAT
	DB	0F6H		; FILL BYTE FOR FORMAT
	DB	25		; HEAD SETTLE TIME (MILLISECONDS)
	DB	4		; MOTOR START TIME (1/8 SECONDS)

;	ORG	0EFD2H
	ORG	00FD2H
PRINTER_IO:
	JMP	PRINTER_IO_1

;	ORG	0F045H
	ORG	01045H
M1	DW	OFFSET SET_MODE 	;  TABLE OF ROUTINES WITHIN VIDEO I/O
	DW	OFFSET SET_CTYPE
	DW	OFFSET SET_CPOS
	DW	OFFSET READ_CURSOR
	DW	OFFSET READ_LPEN
	DW	OFFSET ACT_DISP_PAGE
	DW	OFFSET SCROLL_UP
	DW	OFFSET SCROLL_DOWN
	DW	OFFSET READ_AC_CURRENT
	DW	OFFSET WRITE_AC_CURRENT
	DW	OFFSET WRITE_C_CURRENT
	DW	OFFSET SET_COLOR
	DW	OFFSET WRITE_DOT
	DW	OFFSET READ_DOT
	DW	OFFSET WRITE_TTY
	DW	OFFSET VIDEO_STATE
M1L	EQU	$-M1

;	ORG	0F065H
	ORG	01065H
VIDEO_IO:
	JMP	VIDEO_IO_1

;-----	VIDEO PARAMETERS --- INIT_TABLE

;;-	ORG	0F0A4H
	ORG	010A4H

VIDEO_PARMS	LABEL	BYTE
	DB	38H,28H,2DH,0AH,1FH,6,19H	; SET UP FOR 40X25
	DB	1CH,2,7,6,7
	DB	0,0,0,0
M4	EQU	$-VIDEO_PARMS

	DB	71H,50H,5AH,0AH,1FH,6,19H	; SET UP FOR 80X25
	DB	1CH,2,7,6,7
	DB	0,0,0,0

	DB	38H,28H,2DH,0AH,7FH,6,64H	; SETUP FOR GRAPHICS
	DB	70H,2,1,6,7
	DB	0,0,0,0

	DB	61H,50H,52H,0FH,19H,6,19H	; SETUP FOR 80X25 B&W CARD
	DB	19H,2,0DH,0BH,0CH
	DB	0,0,0,0
					; TABLE OF REGEN LENGTHS
M5	DW	2048			; 40X25
	DW	4096			; 80X25
	DW	16384			; GRAPHICS
	DW	16384

;-----	COLUMNS
M6	DB	40,40,80,80,40,40,80,80

;-----	C_REG_TAB
M7	DB	2CH,28H,2DH,29H,2AH,2EH,1EH,29H ; TABLE OF MODE SETS
PAGE
;--- INT 12 -------------------------------------------------------------
; MEMORY_SIZE_DET							:
;	THIS ROUTINE DETERMINES THE AMOUNT OF MEMORY IN THE SYSTEM	:
;	AS REPRESENTED BY THE SWITCHES ON THE PLANAR. NOTE THAT THE	:
;	SYSTEM MAY NOT BE ABLE TO USE I/O MEMORY UNLESS THERE IS A FULL :
;	COMPLEMENT OF 64K BYTES ON THE PLANAR.				:
; INPUT 								:
;	NO REGISTERS							:
;	THE MEMORY_SIZE VARIABLE IS SET DURING POWER ON DIAGNOSTICS	:
;	 ACCORDING TO THE FOLLOWING HARDWARE ASSUMPTIONS:		:
;	PORT 60 BITS 3,2 = 00 - 16K BASE RAM				:
;			   01 - 32K BASE RAM				:
;			   10 - 48K BASE RAM				:
;			   11 - 64K BASE RAM				:
;	PORT 62 BITS 3-0 INDICATE AMOUNT OF I/O RAM IN 32K INCREMENTS	:
;		E.G., 0000 - NO RAM IN I/O CHANNEL			:
;		      0010 - 64K RAM IN I/O CHANNEL, ETC.		:
; OUTPUT								:
;	(AX) = NUMBER OF CONTIGUOUS 1K BLOCKS OF MEMORY 		:
;------------------------------------------------------------------------
	ASSUME	CS:CODE,DS:DATA
;	ORG	0F841H
	ORG	01841H
MEMORY_SIZE_DET PROC	FAR
	STI				; INTERRUPTS BACK ON
	PUSH	DS			; SAVE SEGMENT
	CALL	DDS
	MOV	AX,@MEMORY_SIZE 	; GET VALUE
	POP	DS			; RECOVER SEGMENT
	IRET				; RETURN TO CALLER
MEMORY_SIZE_DET  ENDP

;--- INT 11 -------------------------------------------------------------
; EQUIPMENT DETERMINATION						:
;	THIS ROUTINE ATTEMPTS TO DETERMINE WHAT OPTIONAL		:
;	DEVICES ARE ATTACHED TO THE SYSTEM.				:
; INPUT 								:
;	NO REGISTERS							:
;	THE EQUIP_FLAG VARIABLE IS SET DURING THE POWER ON		:
;	DIAGNOSTICS USING THE FOLLOWING HARDWARE ASSUMPTIONS:		:
;	PORT 60  = LOW ORDER BYTE OF EQUIPMENT				:
;	PORT 3FA = INTERRUPT ID REGISTER OF 8250			:
;		BITS 7-3 ARE ALWAYS 0					:
;	PORT 378 = OUTPUT PORT OF PRINTER -- 8255 PORT THAT		:
;		CAN BE READ AS WELL AS WRITTEN				:
; OUTPUT								:
;	(AX) IS SET, BIT SIGNIFICANT, TO INDICATE ATTACHED I/O		:
;	BIT 15,14 = NUMBER OF PRINTERS ATTACHED 			:
;	BIT 13 NOT USED 						:
;	BIT 12 = GAME I/O ATTACHED					:
;	BIT 11,10,9 = NUMBER OF RS232 CARDS ATTACHED			:
;	BIT 8 UNUSED							:
;	BIT 7,6 = NUMBER OF DISKETTE DRIVES				:
;		00=1, 01=2, 10-3, 11=4 ONLY IF BIT 0 = 1		:
;	BIT 5,4 = INITIAL VIDEO MODE					:
;			00 - UNUSED					:
;			01 - 40X25 BW USING COLOR CARD			:
;			10 - 80X25 BW USING COLOR CARD			:
;			11 - 80X25 BW USING BW CARD			:
;	BIT 3,2 = PLANAR RAM SIZE (00=256K,01=512K,10=576K,11=64K0)	:
;	BIT 1 = MATH COPROCESSOR					:
;	BIT 0 = IPL FROM DISKETTE -- THIS BIT INDICATES THAT		:
;		THERE ARE DISKETTE DRIVES ON THE SYSTEM 		:
;									:
;	NO OTHER REGISTERS AFFECTED					:
;------------------------------------------------------------------------
	ASSUME	CS:CODE,DS:DATA
;	ORG	0F84DH
	ORG	0184DH
EQUIPMENT	PROC	FAR
	STI			; INTERRUPTS BACK ON
	PUSH	DS		; SAVE SEGMENT REGISTER
	CALL	DDS
	MOV	AX,@EQUIP_FLAG	; GET THE CURRENT SETTINGS
	POP	DS		; RECOVER SEGMENT
	IRET			; RETURN TO CALLER
EQUIPMENT	ENDP

;--- INT 15 -------------------------------------------------------------
;
;	ORG	0F859H
	ORG	01859H
CASSETTE_IO:
	JMP	CASSETTE_IO_1

;----------------------------------------------------------------
; NON-MASKABLE INTERRUPT ROUTINE:				:
;	THIS ROUTINE WILL PRINT A "PARITY CHECK 1 OR 2" MESSAGE :
;	AND ATTEMPT TO FIND THE STORAGE LOCATION CONTAINING THE :
;	BAD PARITY.  IF FOUND, THE SEGMENT ADDRESS WILL BE	:
;	PRINTED.  IF NO PARITY ERROR CAN BE FOUND (INTERMITTANT :
;	READ PROBLEM) ?????<-WILL BE PRINTED WHERE THE ADDRESS	:
;	WOULD NORMALLY GO.					:
;----------------------------------------------------------------
NMI_INT_1	PROC	NEAR
	ASSUME	DS:DATA
	PUSH	AX			; SAVE ORIG CONTENTS OF AX
	IN	AL,PORT_C
	TEST	AL,0C0H 		; PARITY CHECK?
	JNZ	NMI_1
	POP	AX			; RESTORE ORIG CONTENTS OF AX
	IRET
NMI_1:
	PUSH	AX
	XOR	AX,AX
	OUT	0A0H,AL
	CALL	DDS
	MOV	AL,@CRT_MODE
	INT	10H			; CALL VIDEO_IO PROCEDURE
	POP	AX
	MOV	SI,OFFSET D1		; ADDR OF ERROR MSG
	TEST	AL,80H
	JZ	D12
	PUSH	AX
	CALL	P_MSG			; PRINT ERROR MSG
	POP	AX
D12:
	MOV	SI,OFFSET D2		; MUST BE PLANAR
	TEST	AL,40H			; I/O PARITY CHECK?
	JZ	D13
	CALL	P_MSG			; PRINT ERROR MSG
D13:

;----- SET IF LOCATION THAT CAUSED PARITY CHECK CAN BE FOUND

	IN	AL,PORT_B
	OR	AL,00110000B		; TOGGLE PARITY CHECK ENABLES
	OUT	PORT_B,AL
	AND	AL,11001111B
	OUT	PORT_B,AL
	CLD				; SET DIR FLAG TO INCREMENT
	SUB	DX,DX			; POINT DX AT START OF MEM
	IN	AL,PORT_C		; SEE IF PARITY CHECK HAPPENED
	TEST	AL,11000000B
	JNZ	PRT_ERR
	MOV	BX,@MEMORY_SIZE 	; GET MEMORY SIZE WORD
NMI_LOOP:
	MOV	DS,DX
	SUB	SI,SI
	MOV	CX,8
	REP	LODSW
	IN	AL,PORT_C		; SEE IF PARITY CHECK HAPPENED
	TEST	AL,11000000B
	JNZ	PRT_NMI
	INC	DX
	TEST	DX,0FFFH
	JNZ	NMI_LOOP
	SUB	BX,64D
	JA	NMI_LOOP
PRT_ERR:
	MOV	SI,(OFFSET D2A) 	; PRINT ROW OF ????? IF PARITY
	CALL	P_MSG			; CHECK COULD NOT BE RE-CREATED
	CLI
	HLT				; HALT SYSTEM
PRT_NMI:
	CALL	PRT_SEG 		; PRINT SEGMENT VALUE
	CLI
	HLT				; HALT SYSTEM
NMI_INT_1	ENDP

;----------------------------------------
;	ROS CHECKSUM SUBROUTINE 	:
;----------------------------------------
ROS_CHECKSUM	PROC	NEAR		; NEXT_ROS_MODULE
	MOV	CX,0			; NUMBER OF BYTES TO ADD
ROS_CHECKSUM_CNT:			; ENTRY FOR OPTIONAL ROS TEST
	XOR	AL,AL
C26:
	ADD	AL,DS:[BX]
	INC	BX			; POINT TO NEXT BYTE
	LOOP	C26			; ADD ALL BYTES IN ROS MODULE
	OR	AL,AL			; SUM = 0?
	RET
ROS_CHECKSUM	ENDP

;----------------------------------------
;	MESSAGE AREA FOR POST		:
;----------------------------------------
E0	DB	'101',13,10
E1	DB	' 201',13,10
F3A	DB	'ROM',13,10
F3C	DB	'1801',13,10
D1	DB	'PARITY CHECK 1',13,10
D2	DB	'PARITY CHECK 2',13,10
D2A	DB	'?????',13,10

;---------------------------------------------------------------------------
;	BLINK LED PROCEDURE FOR MFG RUN-IN TESTS
;	 IF LED IS ON, TURN IT OFF. IF OFF, TURN ON.
;---------------------------------------------------------------------------
BLINK_INT	PROC	NEAR
	STI
	PUSH	AX			; SAVE AX REG CONTENTS
	IN	AL,PORT_B		; READ CURRENT VAL OF PORT B
	XOR	AL,01000000B		; TOGGLE CONTROL BIT
	OUT	PORT_B,AL
	MOV	AL,EOI
	OUT	INTA00,AL
	POP	AX			; RESTORE AX REG
	IRET
BLINK_INT	ENDP

;--------------------------------------------------------
; THIS ROUTINE CHECKSUMS OPTIONAL ROM MODULES AND	:
; IF CHECKSUM IS OK, CALLS INIT/TEST CODE IN MODULE	:
;--------------------------------------------------------
ROM_CHECK	PROC	NEAR
	MOV	AX,DATA 		; POINT ES TO DATA AREA
	MOV	ES,AX
	SUB	AH,AH			; ZERO OUT AH
	MOV	AL,[BX+2]		; GET LENGTH INDICATOR
	MOV	CL,09H			; MULTIPLY BY 512
	SHL	AX,CL
	MOV	CX,AX			; SET COUNT
	PUSH	CX			; SAVE COUNT
	MOV	CX,4			; ADJUST
	SHR	AX,CL
	ADD	DX,AX			; SET POINTER TO NEXT MODULE
	POP	CX			; RETRIVE COUNT
	CALL	ROS_CHECKSUM_CNT	; DO CHECKSUM
	JZ	ROM_CHECK_1
	CALL	ROM_ERR 		; POST CHECKSUM ERROR
	JMP	SHORT ROM_CHECK_END	; AND EXIT
ROM_CHECK_1:
	PUSH	DX			; SAVE POINTER
	MOV	ES:@IO_ROM_INIT,0003H	; LOAD OFFSET
	MOV	ES:@IO_ROM_SEG,DS	; LOAD SEGMENT
	CALL	DWORD PTR ES:@IO_ROM_INIT	; CALL INIT./TEST ROUTINE
	POP	DX
ROM_CHECK_END:
	RET				; RETURN TO CALLER
ROM_CHECK	ENDP

;------------------------------------------------
; CONVERT AND PRINT ASCII CODE			:
;	AL MUST CONTAIN NUMBER TO BE CONVERTED. :
;	AX AND BX DESTROYED.			:
;------------------------------------------------
XPC_BYTE	PROC	NEAR
	PUSH	AX			; SAVE FOR LOW NYBBLE DISPLAY
	MOV	CL,4			; SHIFT COUNT
	SHR	AL,CL			; NYBBLE SWAP
	CALL	XLAT_PR 		; DO THE HIGH NIBBLE DISPLAY
	POP	AX			; RECOVER THE NIBBLE
	AND	AL,0FH			; ISOLATE TO LOW NIBBLE
					; FALL INTO NIBBLE CONVERSION
XLAT_PR PROC	NEAR			;  CONVERT 00-0F TO ASCII CHARACTER
	ADD	AL,090H 		; ADD FIRST CONVERSION FACTOR
	DAA				; ADJUST FOR NUMERIC AND ALPHA RANGE
	ADC	AL,040H 		; ADD CONVERSION AND ADJUST LOW NIBBLE
	DAA				; ADJUST HI NIBBLE TO ASCII RANGE
PRT_HEX PROC	NEAR
	MOV	AH,14			; DISPLAY CHARACTER IN AL
	MOV	BH,0
	INT	10H			; CALL VIDEO_IO
	RET
PRT_HEX ENDP
XLAT_PR ENDP
XPC_BYTE	ENDP

F4	LABEL	WORD			; PRINTER SOURCE TABLE
	DW	3BCH
	DW	378H
	DW	278H
F4E	LABEL	WORD

;--------------------------------------------------------
; THIS SUBROUTINE WILL PRINT A MESSAGE ON THE DISPLAY	:
;							:
; ENTRY REQUIREMENTS:					:
;	SI = OFFSET(ADDRESS) OF MESSAGE BUFFER		:
;	CX = MESSAGE BYTE COUNT 			:
;	MAXIMUM MESSAGE LENGTH IS 36 CHARACTERS 	:
;--------------------------------------------------------
E_MSG	PROC	NEAR
	MOV	BP,SI			; SET BP NON-ZERO TO FLAG ERR
	CALL	P_MSG			; PRINT MESSAGE
	PUSH	DS
	CALL	DDS
	MOV	AL,BYTE PTR @EQUIP_FLAG ; LOOP/HALT ON ERROR
	AND	AL,01H			; SWITCH ON?
	JNZ	G12			; NO - RETURN
MFG_HALT:
	CLI				; YES -  HALT SYSTEM
	MOV	AL,89H
	OUT	CMD_PORT,AL
	MOV	AL,10000101B		; DISABLE KB
	OUT	PORT_B,AL
	MOV	AL,@MFG_ERR_FLAG	; RECOVER ERROR INDICATOR
	OUT	PORT_A,AL		; SET INTO 8255 REG
	HLT				; HALT SYS
G12:
	POP	DS			; WRITE_MSG:
	RET
E_MSG	ENDP

P_MSG	PROC	NEAR
G12A:
	MOV	AL,CS:[SI]		; PUT CHAR IN AL
	INC	SI			; POINT TO NEXT CHAR
	PUSH	AX			; SAVE PRINT CHAR
	CALL	PRT_HEX 		; CALL VIDEO_IO
	POP	AX			; RECOVER PRINT CHAR
	CMP	AL,10			; WAS IT LINE FEED?
	JNE	G12A				; NO,KEEP PRINTING STRING
	RET
P_MSG	ENDP
	ASSUME	CS:CODE,DS:DATA
;------------------------------------------------------------------------
;	THIS PROCEDURE WILL ISSUE LONG TONES (1-3/4 SECONDS) AND ONE OR :
;	MORE SHORT TONES (9/32 SECOND) TO INDICATE A FAILURE ON THE	:
;	PLANAR BOARD, A BAD MEMORY MODULE, OR A PROBLEM WITH THE CRT.	:
;ENTRY PARAMETERS:							:
;	DH = NUMBER OF LONG TONES TO BEEP.				:
;	DL = NUMBER OF SHORT TONES TO BEEP.				:
;------------------------------------------------------------------------

ERR_BEEP  PROC	NEAR
	PUSHF				; SAVE FLAGS
	CLI				; DISABLE SYSTEM INTERRUPTS
	OR	DH,DH			; ANY LONG ONES TO BEEP
	JZ	G3			; NO, DO THE SHORT ONES
G1:					;	LONG BEEPS
	MOV	BL,112			; COUNTER FOR LONG BEEPS (1-3/4 SECONDS)
	MOV	CX,1280 		; DIVISOR FOR 932 HZ
	CALL	BEEP			; DO THE BEEP
	MOV	CX,49715		; 2/3 SECOND DELAY AFTER LONG BEEP
	CALL	WAITF			; DELAY BETWEEN BEEPS
	DEC	DH			; ANY MORE LONG BEEPS TO DO
	JNZ	G1			; LOOP TILL DONE
	PUSH	DS			; SAVE DS REGISTER CONTENTS
	CALL	DDS
	CMP	@MFG_TST,01H		; MFG TEST MODE?
	POP	DS			; RESTORE ORIGINAL CONTENTS OF (DS)
	JE	MFG_HALT		; YES - STOP BLINKING LED
G3:					;	SHORT BEEPS
	MOV	BL,18			; COUNTER FOR A SHORT BEEP (9/32)
	MOV	CX,1208 		; DIVISOR FOR 987 HZ
	CALL	BEEP			; DO THE SOUND
	MOV	CX,33144		; 1/2 SECOND DELAY AFTER SHORT BEEP
	CALL	WAITF			; DELAY BETWEEN BEEPS
	DEC	DL			; DONE WITH SHORT BEEPS COUNT
	JNZ	G3			; LOOP TILL DONE
	MOV	CX,33144		; 1/2 SECOND DELAY AFTER LAST BEEP
	CALL	WAITF			; MAKE IT ONE SECOND DELAY BEFORE RETURN
	POPF				; RESTORE FLAGS TO ORIGINAL SETTINGS
	RET				; RETURN TO CALLER
ERR_BEEP	ENDP

;------------------------------------------------------------------------
;	THIS PROCEDURE WILL SEND A SOFTWARE RESET TO THE KEYBOARD.	:
;	SCAN CODE 'AA' SHOULD BE RETURNED TO THE CPU.                   :
;------------------------------------------------------------------------
KBD_RESET	PROC	NEAR
	ASSUME	DS:ABS0
	MOV	AL,08H			; SET KBD CLK LINE LOW
	OUT	PORT_B,AL		; WRITE 8255 PORT B
	MOV	CX,10582		; HOLD KBD CLK LOW FOR 20 MS
G8:
	LOOP	G8			; LOOP FOR 20 MS
	MOV	AL,0C8H 		; SET CLK, ENABLE LINES HIGH
	OUT	PORT_B,AL
SP_TEST:				; ENTRY FOR MANUFACTURING TEST 2
	MOV	AL,48H			; SET KBD CLK HIGH, ENABLE LOW
	OUT	PORT_B,AL
	MOV	AL,0FDH 		; ENABLE KEYBOARD INTERRUPTS
	OUT	INTA01,AL		; WRITE 8255 IMR
	MOV	DATA_AREA[@INTR_FLAG-DATA40],0	; RESET INTERRUPT INDICATOR
	STI				; ENABLE INTERRUPTS
	SUB	CX,CX			; SETUP INTERRUPT TIMEOUT CNT
G9:
	TEST	DATA_AREA[@INTR_FLAG-DATA40],02H ; DID A KEYBOARD INTR OCCUR?
	JNZ	G10			; YES - READ SCAN CODE RETURNED
	LOOP	G9			; NO - LOOP TILL TIMEOUT
G10:
	IN	AL,PORT_A		; READ KEYBOARD SCAN CODE
	MOV	BL,AL			; SAVE SCAN CODE JUST READ
	MOV	AL,0C8H 		; CLEAR KEYBOARD
	OUT	PORT_B,AL
	RET				; RETURN TO CALLER
KBD_RESET	ENDP

DDS	PROC	NEAR			;	LOAD (DS) TO DATA AREA
	MOV	DS,CS:DDSDATA		; PUT SEGMENT VALUE OF DATA AREA INTO DS
	RET				; RETURN TO USER WITH (DS)= DATA

DDSDATA DW	DATA			; SEGMENT SELECTOR VALUE FOR DATA AREA
DDS	ENDP

;-- HARDWARE INT  08 H - ( IRQ LEVEL 0 ) ---------------------------------------
;	THIS ROUTINE HANDLES THE TIMER INTERRUPT FROM FROM CHANNEL 0 OF        :
;	THE 8254 TIMER.  INPUT FREQUENCY IS 1.19318 MHZ AND THE DIVISOR        :
;	IS 65536, RESULTING IN APPROXIMATELY 18.2 INTERRUPTS EVERY SECOND.     :
;									       :
;	THE INTERRUPT HANDLER MAINTAINS A COUNT (40:6C) OF INTERRUPTS SINCE    :
;	POWER ON TIME, WHICH MAY BE USED TO ESTABLISH TIME OF DAY.	       :
;	THE INTERRUPT HANDLER ALSO DECREMENTS THE MOTOR CONTROL COUNT (40:40)  :
;	OF THE DISKETTE, AND WHEN IT EXPIRES, WILL TURN OFF THE 	       :
;	DISKETTE MOTOR(s), AND RESET THE MOTOR RUNNING FLAGS.		       :
;	THE INTERRUPT HANDLER WILL ALSO INVOKE A USER ROUTINE THROUGH	       :
;	INTERRUPT 1CH AT EVERY TIME TICK.  THE USER MUST CODE A 	       :
;	ROUTINE AND PLACE THE CORRECT ADDRESS IN THE VECTOR TABLE.	       :
;-------------------------------------------------------------------------------
	ASSUME	CS:CODE,DS:DATA

TIMER_INT_1	PROC	NEAR
	STI				; INTERRUPTS BACK ON
	PUSH	DS
	PUSH	AX
	PUSH	DX			; SAVE MACHINE STATE
	MOV	AX,DATA 		; GET ADDRESS OF DATA SEGMENT
	MOV	DS,AX			; ESTABLISH ADDRESSABILITY
	INC	@TIMER_LOW		; INCREMENT TIME
	JNZ	T4			; GO TO TEST_DAY
	INC	@TIMER_HIGH		; INCREMENT HIGH WORD OF TIME
T4:					;	TEST_DAY
	CMP	@TIMER_HIGH,018H	; TEST FOR COUNT EQUALING 24 HOURS
	JNZ	T5			; GO TO DISKETTE_CTL
	CMP	@TIMER_LOW,0B0H
	JNZ	T5			; GO TO DISKETTE_CTL

;-----	TIMER HAS GONE 24 HOURS

	SUB	AX,AX
	MOV	@TIMER_HIGH,AX		; CLEAR TIMER COUNT HIGH
	MOV	@TIMER_LOW,AX		;  AND LOW
	MOV	@TIMER_OFL,1		; SET TIMER ELAPSED 24 HOURS FLAG
	INC	@DAY_COUNT		; INCREMENT ELAPSED DAY COUNTER

;-----	TEST FOR DISKETTE TIME OUT

T5:
	DEC	@MOTOR_COUNT		; DECREMENT DISKETTE MOTOR CONTROL
	JNZ	T6			; RETURN IF COUNT NOT OUT
	AND	@MOTOR_STATUS,0F0H	; TURN OFF MOTOR RUNNING BITS
	MOV	AL,0CH
	MOV	DX,03F2H		; FDC CTL PORT
	OUT	DX,AL			; TURN OFF THE MOTOR

T6:					;	TIMER TICK INTERRUPT
	INT	1CH			; TRANSFER CONTROL TO A USER ROUTINE

	CLI				; DISABLE INTERRUPTS TILL STACK CLEARED
	MOV	AL,EOI			; GET END OF INTERRUPT MASK
	OUT	INTA00,AL		; END OF INTERRUPT TO 8259
	POP	DX
	POP	AX
	POP	DS			; RESET MACHINE STATE
	IRET				;  RETURN FROM INTERRUPT

TIMER_INT_1	 ENDP
PAGE
;----------------------------------------------------------------------
; CHARACTER GENERATOR GRAPHICS FOR 320X200 AND 640X200 GRAPHICS       :
;----------------------------------------------------------------------
;	ORG	0FA6EH
	ORG	01A6EH
CRT_CHAR_GEN	LABEL	BYTE
	DB	000H,000H,000H,000H,000H,000H,000H,000H ; D_00	BLANK
	DB	07EH,081H,0A5H,081H,0BDH,099H,081H,07EH ; D_01	SMILING FACE
	DB	07EH,0FFH,0DBH,0FFH,0C3H,0E7H,0FFH,07EH ; D_02	SMILING FACE N
	DB	06CH,0FEH,0FEH,0FEH,07CH,038H,010H,000H ; D_03	HEART
	DB	010H,038H,07CH,0FEH,07CH,038H,010H,000H ; D_04	DIAMOND
	DB	038H,07CH,038H,0FEH,0FEH,07CH,038H,07CH ; D_05	CLUB
	DB	010H,010H,038H,07CH,0FEH,07CH,038H,07CH ; D_06	SPADE
	DB	000H,000H,018H,03CH,03CH,018H,000H,000H ; D_07	BULLET
	DB	0FFH,0FFH,0E7H,0C3H,0C3H,0E7H,0FFH,0FFH ; D_08	BULLET NEG
	DB	000H,03CH,066H,042H,042H,066H,03CH,000H ; D_09	CIRCLE
	DB	0FFH,0C3H,099H,0BDH,0BDH,099H,0C3H,0FFH ; D_0A	CIRCLE NEG
	DB	00FH,007H,00FH,07DH,0CCH,0CCH,0CCH,078H ; D_0B	MALE
	DB	03CH,066H,066H,066H,03CH,018H,07EH,018H ; D_0C	FEMALE
	DB	03FH,033H,03FH,030H,030H,070H,0F0H,0E0H ; D_0D	EIGHTH NOTE
	DB	07FH,063H,07FH,063H,063H,067H,0E6H,0C0H ; D_0E	TWO 1/16 NOTE
	DB	099H,05AH,03CH,0E7H,0E7H,03CH,05AH,099H ; D_0F	SUN

	DB	080H,0E0H,0F8H,0FEH,0F8H,0E0H,080H,000H ; D_10	R ARROWHEAD
	DB	002H,00EH,03EH,0FEH,03EH,00EH,002H,000H ; D_11	L ARROWHEAD
	DB	018H,03CH,07EH,018H,018H,07EH,03CH,018H ; D_12	ARROW 2 VERT
	DB	066H,066H,066H,066H,066H,000H,066H,000H ; D_13	2 EXCLAMATIONS
	DB	07FH,0DBH,0DBH,07BH,01BH,01BH,01BH,000H ; D_14	PARAGRAPH
	DB	03EH,063H,038H,06CH,06CH,038H,0CCH,078H ; D_15	SECTION
	DB	000H,000H,000H,000H,07EH,07EH,07EH,000H ; D_16	RECTANGLE
	DB	018H,03CH,07EH,018H,07EH,03CH,018H,0FFH ; D_17	ARROW 2 VRT UP
	DB	018H,03CH,07EH,018H,018H,018H,018H,000H ; D_18	ARROW VRT UP
	DB	018H,018H,018H,018H,07EH,03CH,018H,000H ; D_19	ARROW VRT DOWN
	DB	000H,018H,00CH,0FEH,00CH,018H,000H,000H ; D_1A	ARROW RIGHT
	DB	000H,030H,060H,0FEH,060H,030H,000H,000H ; D_1B	ARROW LEFT
	DB	000H,000H,0C0H,0C0H,0C0H,0FEH,000H,000H ; D_1C	NOT INVERTED
	DB	000H,024H,066H,0FFH,066H,024H,000H,000H ; D_1D	ARROW 2 HORZ
	DB	000H,018H,03CH,07EH,0FFH,0FFH,000H,000H ; D_1E	ARROWHEAD UP
	DB	000H,0FFH,0FFH,07EH,03CH,018H,000H,000H ; D_1F	ARROWHEAD DOWN

	DB	000H,000H,000H,000H,000H,000H,000H,000H ; D_20	SPACE
	DB	030H,078H,078H,030H,030H,000H,030H,000H ; D_21 ! EXCLAMATION
	DB	06CH,06CH,06CH,000H,000H,000H,000H,000H ; D_22 " QUOTATION
	DB	06CH,06CH,0FEH,06CH,0FEH,06CH,06CH,000H ; D_23 # LB.
	DB	030H,07CH,0C0H,078H,00CH,0F8H,030H,000H ; D_24 $ DOLLAR SIGN
	DB	000H,0C6H,0CCH,018H,030H,066H,0C6H,000H ; D_25 % PERCENT
	DB	038H,06CH,038H,076H,0DCH,0CCH,076H,000H ; D_26 & AMPERSAND
	DB	060H,060H,0C0H,000H,000H,000H,000H,000H ; D_27 ' APOSTROPHE
	DB	018H,030H,060H,060H,060H,030H,018H,000H ; D_28 ( L. PARENTHESIS
	DB	060H,030H,018H,018H,018H,030H,060H,000H ; D_29 ) R. PARENTHESIS
	DB	000H,066H,03CH,0FFH,03CH,066H,000H,000H ; D_2A * ASTERISK
	DB	000H,030H,030H,0FCH,030H,030H,000H,000H ; D_2B + PLUS
	DB	000H,000H,000H,000H,000H,030H,030H,060H ; D_2C , COMMA
	DB	000H,000H,000H,0FCH,000H,000H,000H,000H ; D_2D - DASH
	DB	000H,000H,000H,000H,000H,030H,030H,000H ; D_2E . PERIOD
	DB	006H,00CH,018H,030H,060H,0C0H,080H,000H ; D_2F / SLASH

	DB	07CH,0C6H,0CEH,0DEH,0F6H,0E6H,07CH,000H ; D_30 0
	DB	030H,070H,030H,030H,030H,030H,0FCH,000H ; D_31 1
	DB	078H,0CCH,00CH,038H,060H,0CCH,0FCH,000H ; D_32 2
	DB	078H,0CCH,00CH,038H,00CH,0CCH,078H,000H ; D_33 3
	DB	01CH,03CH,06CH,0CCH,0FEH,00CH,01EH,000H ; D_34 4
	DB	0FCH,0C0H,0F8H,00CH,00CH,0CCH,078H,000H ; D_35 5
	DB	038H,060H,0C0H,0F8H,0CCH,0CCH,078H,000H ; D_36 6
	DB	0FCH,0CCH,00CH,018H,030H,030H,030H,000H ; D_37 7
	DB	078H,0CCH,0CCH,078H,0CCH,0CCH,078H,000H ; D_38 8
	DB	078H,0CCH,0CCH,07CH,00CH,018H,070H,000H ; D_39 9
	DB	000H,030H,030H,000H,000H,030H,030H,000H ; D_3A : COLON
	DB	000H,030H,030H,000H,000H,030H,030H,060H ; D_3B ; SEMICOLON
	DB	018H,030H,060H,0C0H,060H,030H,018H,000H ; D_3C < LESS THAN
	DB	000H,000H,0FCH,000H,000H,0FCH,000H,000H ; D_3D = EQUAL
	DB	060H,030H,018H,00CH,018H,030H,060H,000H ; D_3E > GREATER THAN
	DB	078H,0CCH,00CH,018H,030H,000H,030H,000H ; D_3F ? QUESTION MARK

	DB	07CH,0C6H,0DEH,0DEH,0DEH,0C0H,078H,000H ; D_40 @ AT
	DB	030H,078H,0CCH,0CCH,0FCH,0CCH,0CCH,000H ; D_41 A
	DB	0FCH,066H,066H,07CH,066H,066H,0FCH,000H ; D_42 B
	DB	03CH,066H,0C0H,0C0H,0C0H,066H,03CH,000H ; D_43 C
	DB	0F8H,06CH,066H,066H,066H,06CH,0F8H,000H ; D_44 D
	DB	0FEH,062H,068H,078H,068H,062H,0FEH,000H ; D_45 E
	DB	0FEH,062H,068H,078H,068H,060H,0F0H,000H ; D_46 F
	DB	03CH,066H,0C0H,0C0H,0CEH,066H,03EH,000H ; D_47 G
	DB	0CCH,0CCH,0CCH,0FCH,0CCH,0CCH,0CCH,000H ; D_48 H
	DB	078H,030H,030H,030H,030H,030H,078H,000H ; D_49 I
	DB	01EH,00CH,00CH,00CH,0CCH,0CCH,078H,000H ; D_4A J
	DB	0E6H,066H,06CH,078H,06CH,066H,0E6H,000H ; D_4B K
	DB	0F0H,060H,060H,060H,062H,066H,0FEH,000H ; D_4C L
	DB	0C6H,0EEH,0FEH,0FEH,0D6H,0C6H,0C6H,000H ; D_4D M
	DB	0C6H,0E6H,0F6H,0DEH,0CEH,0C6H,0C6H,000H ; D_4E N
	DB	038H,06CH,0C6H,0C6H,0C6H,06CH,038H,000H ; D_4F O

	DB	0FCH,066H,066H,07CH,060H,060H,0F0H,000H ; D_50 P
	DB	078H,0CCH,0CCH,0CCH,0DCH,078H,01CH,000H ; D_51 Q
	DB	0FCH,066H,066H,07CH,06CH,066H,0E6H,000H ; D_52 R
	DB	078H,0CCH,0E0H,070H,01CH,0CCH,078H,000H ; D_53 S
	DB	0FCH,0B4H,030H,030H,030H,030H,078H,000H ; D_54 T
	DB	0CCH,0CCH,0CCH,0CCH,0CCH,0CCH,0FCH,000H ; D_55 U
	DB	0CCH,0CCH,0CCH,0CCH,0CCH,078H,030H,000H ; D_56 V
	DB	0C6H,0C6H,0C6H,0D6H,0FEH,0EEH,0C6H,000H ; D_57 W
	DB	0C6H,0C6H,06CH,038H,038H,06CH,0C6H,000H ; D_58 X
	DB	0CCH,0CCH,0CCH,078H,030H,030H,078H,000H ; D_59 Y
	DB	0FEH,0C6H,08CH,018H,032H,066H,0FEH,000H ; D_5A Z
	DB	078H,060H,060H,060H,060H,060H,078H,000H ; D_5B [ LEFT BRACKET
	DB	0C0H,060H,030H,018H,00CH,006H,002H,000H ; D_5C \ BACKSLASH
	DB	078H,018H,018H,018H,018H,018H,078H,000H ; D_5D ] RIGHT BRACKET
	DB	010H,038H,06CH,0C6H,000H,000H,000H,000H ; D_5E ^ CIRCUMFLEX
	DB	000H,000H,000H,000H,000H,000H,000H,0FFH ; D_5F _ UNDERSCORE

	DB	030H,030H,018H,000H,000H,000H,000H,000H ; D_60 ` APOSTROPHE REV
	DB	000H,000H,078H,00CH,07CH,0CCH,076H,000H ; D_61 a
	DB	0E0H,060H,060H,07CH,066H,066H,0DCH,000H ; D_62 b
	DB	000H,000H,078H,0CCH,0C0H,0CCH,078H,000H ; D_63 c
	DB	01CH,00CH,00CH,07CH,0CCH,0CCH,076H,000H ; D_64 d
	DB	000H,000H,078H,0CCH,0FCH,0C0H,078H,000H ; D_65 e
	DB	038H,06CH,060H,0F0H,060H,060H,0F0H,000H ; D_66 f
	DB	000H,000H,076H,0CCH,0CCH,07CH,00CH,0F8H ; D_67 g
	DB	0E0H,060H,06CH,076H,066H,066H,0E6H,000H ; D_68 h
	DB	030H,000H,070H,030H,030H,030H,078H,000H ; D_69 i
	DB	00CH,000H,00CH,00CH,00CH,0CCH,0CCH,078H ; D_6A j
	DB	0E0H,060H,066H,06CH,078H,06CH,0E6H,000H ; D_6B k
	DB	070H,030H,030H,030H,030H,030H,078H,000H ; D_6C l
	DB	000H,000H,0CCH,0FEH,0FEH,0D6H,0C6H,000H ; D_6D m
	DB	000H,000H,0F8H,0CCH,0CCH,0CCH,0CCH,000H ; D_6E n
	DB	000H,000H,078H,0CCH,0CCH,0CCH,078H,000H ; D_6F o

	DB	000H,000H,0DCH,066H,066H,07CH,060H,0F0H ; D_70 p
	DB	000H,000H,076H,0CCH,0CCH,07CH,00CH,01EH ; D_71 q
	DB	000H,000H,0DCH,076H,066H,060H,0F0H,000H ; D_72 r
	DB	000H,000H,07CH,0C0H,078H,00CH,0F8H,000H ; D_73 s
	DB	010H,030H,07CH,030H,030H,034H,018H,000H ; D_74 t
	DB	000H,000H,0CCH,0CCH,0CCH,0CCH,076H,000H ; D_75 u
	DB	000H,000H,0CCH,0CCH,0CCH,078H,030H,000H ; D_76 v
	DB	000H,000H,0C6H,0D6H,0FEH,0FEH,06CH,000H ; D_77 w
	DB	000H,000H,0C6H,06CH,038H,06CH,0C6H,000H ; D_78 x
	DB	000H,000H,0CCH,0CCH,0CCH,07CH,00CH,0F8H ; D_79 y
	DB	000H,000H,0FCH,098H,030H,064H,0FCH,000H ; D_7A z
	DB	01CH,030H,030H,0E0H,030H,030H,01CH,000H ; D_7B { LEFT BRACE
	DB	018H,018H,018H,000H,018H,018H,018H,000H ; D_7C | BROKEN STROKE
	DB	0E0H,030H,030H,01CH,030H,030H,0E0H,000H ; D_7D } RIGHT BRACE
	DB	076H,0DCH,000H,000H,000H,000H,000H,000H ; D_7E ~ TILDE
	DB	000H,010H,038H,06CH,0C6H,0C6H,0FEH,000H ; D_7F  DELTA
PAGE
;--- INT 1A ---------------------------------------------
; TIME_OF_DAY						:
;  THIS ROUTINE ALLOWS THE CLOCK TO BE SET/READ 	:
;							:
; INPUT 						:
;   (AH) = 0	READ THE CURRENT CLOCK SETTING		:
;		RETURNS CX = HIGH PORTION OF COUNT	:
;			DX = LOW PORTION OF COUNT	:
;			AL = 0 IF TIMER HAS NOT PASSED	:
;			 24 HOURS SINCE LAST READ	:
;			   <>0 IF ON ANOTHER DAY	:
;   (AH) = 1	SET THE CURRENT CLOCK			:
;	CX = HIGH PORTION OF COUNT			:
;	DX = LOW PORTION OF COUNT			:
; NOTE: COUNTS OCCUR AT THE RATE OF			:
;	 1193180/65536 COUNTS/SEC			:
;	(OR ABOUT 18.2 PER SECOND -- SEE EQUATES BELOW) :
;--------------------------------------------------------
;	ORG	0FE6EH
	ORG	01E6EH
TIME_OF_DAY:
	JMP	TIME_OF_DAY_11

;	ORG	0FEA5H
	ORG	01EA5H
TIMER_INT:
	JMP	TIMER_INT_1

;------------------------------------------------
; THESE ARE THE VECTORS WHICH ARE MOVED INTO	:
; THE 8086 INTERRUPT AREA DURING POWER ON.	:
; ONLY THE OFFSETS ARE DISPLAYED HERE, CODE	:
; SEGMENT WILL BE ADDED FOR ALL OF THEM, EXCEPT :
; WHERE NOTED.					:
;------------------------------------------------
	ASSUME	CS:CODE
;	ORG	0FEF3H
	ORG	01EF3H			;	AT LOCATION 0FEF3H
VECTOR_TABLE	LABEL	WORD		; VECTOR TABLE VALUES FOR POST TESTS
	DW	OFFSET TIMER_INT	; INT 08H - HARDWARE TIMER 0	  IRQ  0
	DW	OFFSET KB_INT		; INT 09H - KEYBOARD		  IRQ  1
	DW	OFFSET	D11		; INT 0AH			  IRQ  2
	DW	OFFSET	D11		; INT 0BH -			  IRQ  3
	DW	OFFSET	D11		; INT 0CH -			  IRQ  4
	DW	OFFSET	D11		; INT 0DH -			  IRQ  5
	DW	OFFSET DISK_INT 	; INT 0EH - DISKETTE		  IRQ  6
	DW	OFFSET	D11		; INT 0FH -			  IRQ  7

;-----	SOFTWARE INTERRUPTS  ( BIOS CALLS AND POINTERS )

	DW	OFFSET VIDEO_IO 	; INT 10H -- VIDEO DISPLAY
	DW	OFFSET EQUIPMENT	; INT 11H -- GET EQUIPMENT FLAG WORD
	DW	OFFSET MEMORY_SIZE_DET	; INT 12H -- GET REAL MODE MEMORY SIZE
	DW	OFFSET DISKETTE_IO	; INT 13H -- DISKETTE
	DW	OFFSET RS232_IO 	; INT 14H -- COMMUNICATION ADAPTER
	DW	OFFSET CASSETTE_IO	; INT 15H -- EXPANDED BIOS FUNCTION CALL
	DW	OFFSET KEYBOARD_IO	; INT 16H -- KEYBOARD INPUT
	DW	OFFSET PRINTER_IO	; INT 17H -- PRINTER OUTPUT
	DW	00000H			; INT 18H -- 0F600H INSERTED FOR BASIC
	DW	OFFSET BOOT_STRAP	; INT 19H -- BOOT FROM SYSTEM MEDIA
	DW	OFFSET TIME_OF_DAY	; INT 1AH -- TIME OF DAY
	DW	OFFSET DUMMY_RETURN	; INT 1BH -- KEYBOARD BREAK ADDRESS
	DW	OFFSET DUMMY_RETURN	; INT 1CH -- TIMER BREAK ADDRESS
	DW	OFFSET VIDEO_PARMS	; INT 1DH -- VIDEO PARAMETERS
	DW	OFFSET DISK_BASE	; INT 1EH -- DISKETTE PARAMETERS
	DW	00000H			; INT 1FH -- POINTER TO VIDEO EXTENSION

;--------------------------------------------------------
; TEMPORARY INTERRUPT SERVICE ROUTINE			:
;	1. THIS ROUTINE IS ALSO LEFT IN PLACE AFTER THE :
;	POWER ON DIAGNOSTICS TO SERVICE UNUSED		:
;	INTERRUPT VECTORS. LOCATION 'INTR_FLAG' WILL    :
;	CONTAIN EITHER: 1. LEVEL OF HARDWARE INT. THAT	:
;	CAUSED CODE TO BE EXEC. 			:
;	2. 'FF' FOR NON-HARDWARE INTERUPTS THAT WAS     :
;	EXECUTED ACCIDENTLY.				:
;--------------------------------------------------------
D11	PROC	NEAR
	ASSUME	DS:DATA
	PUSH	DS
	CALL	DDS
	PUSH	AX			; SAVE REG AX CONTENTS
	MOV	AL,0BH			; READ IN-SERVICE REG
	OUT	INTA00,AL		; (FIND OUT WHAT LEVEL BEING
	NOP				; SERVICED)
	IN	AL,INTA00		; GET LEVEL
	MOV	AH,AL			; SAVE IT
	OR	AL,AH			; 00? (NO HARDWARE ISR ACTIVE)
	JNZ	HW_INT
	MOV	AH,0FFH
	JMP	SHORT SET_INTR_FLAG	; SET FLAG TO FF IF NON-HDWARE
HW_INT:
	IN	AL,INTA01		; GET MASK VALUE
	OR	AL,AH			; MASK OFF LVL BEING SERVICED
	OUT	INTA01,AL
	MOV	AL,EOI
	OUT	INTA00,AL
SET_INTR_FLAG:
	MOV	@INTR_FLAG,AH		; SET FLAG
	POP	AX			; RESTORE REG AX CONTENTS
	POP	DS
DUMMY_RETURN:				; NEED IRET FOR VECTOR TABLE
	IRET
D11	ENDP

;------------------------------------------------
; DUMMY RETURN FOR ADDRESS COMPATIBILITY	:
;------------------------------------------------
;	ORG	0FF53H
	ORG	01F53H
	IRET
PAGE
;--- INT  05 H -----------------------------------------------------------------
; PRINT_SCREEN								       :
;	THIS LOGIC WILL BE INVOKED BY INTERRUPT 05H TO PRINT THE SCREEN.       :
;	THE CURSOR POSITION AT THE TIME THIS ROUTINE IS INVOKED WILL BE        :
;	SAVED AND RESTORED UPON COMPLETION.  THE ROUTINE IS INTENDED TO        :
;	RUN WITH INTERRUPTS ENABLED.   IF A SUBSEQUENT PRINT SCREEN KEY        :
;	IS DEPRESSED WHILE THIS ROUTINE IS PRINTING IT WILL BE IGNORED.        :
;	THE BASE PRINTERS STATUS IS CHECKED FOR NOT BUSY AND NOT OUT OF        :
;	PAPER.	AN INITIAL STATUS ERROR WILL ABEND THE PRINT REQUEST.	       :
;	ADDRESS  0050:0000  CONTAINS THE STATUS OF THE PRINT SCREEN:	       :
;									       :
;	50:0	= 0	PRINT SCREEN HAS NOT BEEN CALLED OR UPON RETURN        :
;			 FROM A CALL THIS INDICATES A SUCCESSFUL OPERATION.    :
;		= 1	PRINT SCREEN IS IN PROGRESS - IGNORE THIS REQUEST.     :
;		= 255	ERROR ENCOUNTERED DURING PRINTING.		       :
;-------------------------------------------------------------------------------
;	ORG	0FF54H
	ORG	01F54H

PRINT_SCREEN_1	PROC  FAR
					; DELAY INTERRUPT ENABLE TILL FLAG SET
	PUSH	DS			; USE 0040:0100 FOR STATUS AREA STORAGE
	CALL	DDS			; GET STATUS_BYTE DATA SEGMENT
	CMP	@STATUS_BYTE,1		; SEE IF PRINT ALREADY IN PROGRESS
	JE	PRI90			; EXIT IF PRINT ALREADY IN PROGRESS
	MOV	@STATUS_BYTE,1		; INDICATE PRINT NOW IN PROGRESS
	STI				; MUST RUN WITH INTERRUPTS ENABLED
	PUSH	AX			; SAVE WORK REGISTERS
	PUSH	BX
	PUSH	CX
	PUSH	DX			; USE 0040:0100 FOR STATUS AREA STORAGE
	MOV	AH,0FH			; WILL REQUEST THE CURRENT SCREEN MODE
	INT	10H			;	(AL)= MODE
					;	(AH)= NUMBER COLUMNS/LINE
					;	(BH)= VISUAL PAGE
	MOV	CL,AH			; WILL MAKE USE OF (CX) REGISTER TO
	MOV	CH,@ROWS		;  CONTROL ROWS ON SCREEN & COLUMNS
	INC	CH			; ADJUST ROWS ON DISPLAY COUNT
					;	(CL)= NUMBER COLUMNS/LINE
					;	(CH)= NUMBER OF ROWS ON DISPLAY
	;----------------------------------------------------------------
	;	AT THIS POINT WE KNOW THE COLUMNS/LINE COUNT IS IN (CL) :
	;	AND THE NUMBER OF ROWS ON THE DISPLAY IS IN (CH).	:
	;	THE PAGE IF APPLICABLE IS IN (BH).  THE STACK HAS	:
	;	(DS),(AX),(BX),(CX),(DX) PUSHED.			:
	;----------------------------------------------------------------
	XOR	DX,DX			; FIRST PRINTER
	MOV	AH,02H			; SET PRINTER STATUS REQUEST COMMAND
	INT	17H			; REQUEST CURRENT PRINTER STATUS
	XOR	AH,080H 		; CHECK FOR PRINTER BUSY (NOT CONNECTED)
	TEST	AH,0A0H 		;  OR OUT OF PAPER
	JNZ	PRI70			; ERROR EXIT IF PRINTER STATUS ERROR

	CALL	CRLF			; CARRIAGE RETURN LINE FEED TO PRINTER
	PUSH	CX			; SAVE SCREEN BOUNDS
	MOV	AH,03H			; NOW READ THE CURRENT CURSOR POSITION
	INT	10H			; AND RESTORE AT END OF ROUTINE
	POP	CX			; RECALL SCREEN BOUNDS
	PUSH	DX			; PRESERVE THE ORIGINAL POSITION
	XOR	DX,DX			; INITIAL CURSOR (0,0) AND FIRST PRINTER
	;----------------------------------------------------------------
	;	THIS LOOP IS TO READ EACH CURSOR POSITION FROM THE	:
	;	SCREEN AND PRINT IT.  (BH)= VISUAL PAGE  (CH)= ROWS	:
	;----------------------------------------------------------------
PRI10:
	MOV	AH,02H			; INDICATE CURSOR SET REQUEST
	INT	10H			; NEW CURSOR POSITION ESTABLISHED
	MOV	AH,08H			; INDICATE READ CHARACTER FROM DISPLAY
	INT	10H			; CHARACTER NOW IN (AL)
	OR	AL,AL			; SEE IF VALID CHAR
	JNZ	PRI20			; JUMP IF VALID CHAR
	MOV	AL,' '                  ; ELSE MAKE IT A BLANK
PRI20:
	PUSH	DX			; SAVE CURSOR POSITION
	XOR	DX,DX			; INDICATE FIRST PRINTER (DX= 0)
	XOR	AH,AH			; INDICATE PRINT CHARACTER IN (AL)
	INT	17H			; PRINT THE CHARACTER
	POP	DX			; RECALL CURSOR POSITION
	TEST	AH,29H			; TEST FOR PRINTER ERROR
	JNZ	PRI60			; EXIT IF ERROR DETECTED
	INC	DL			; ADVANCE TO NEXT COLUMN
	CMP	CL,DL			; SEE IF AT END OF LINE
	JNZ	PRI10			; IF NOT LOOP FOR NEXT COLUMN
	XOR	DL,DL			; BACK TO COLUMN 0
	MOV	AH,DL			; (AH)=0
	PUSH	DX			; SAVE NEW CURSOR POSITION
	CALL	CRLF			; LINE FEED CARRIAGE RETURN
	POP	DX			; RECALL CURSOR POSITION
	INC	DH			; ADVANCE TO NEXT LINE
	CMP	CH,DH			; FINISHED?
	JNZ	PRI10			; IF NOT LOOP FOR NEXT LINE

	POP	DX			; GET CURSOR POSITION
	MOV	AH,02H			; INDICATE REQUEST CURSOR SET
	INT	10H			; CURSOR POSITION RESTORED
	CLI				; BLOCK INTERRUPTS TILL STACK CLEARED
	MOV	@STATUS_BYTE,0		; MOVE OK RESULTS FLAG TO STATUS_BYTE
	JMP	SHORT PRI80		; EXIT PRINTER ROUTINE
PAGE
PRI60:					;	ERROR EXIT
	POP	DX			; GET CURSOR POSITION
	MOV	AH,02H			; INDICATE REQUEST CURSOR SET
	INT	10H			; CURSOR POSITION RESTORED
PRI70:
	CLI				; BLOCK INTERRUPTS TILL STACK CLEARED
	MOV	@STATUS_BYTE,0FFH	; SET ERROR FLAG
PRI80:
	POP	DX			;	EXIT ROUTINE
	POP	CX			; RESTORE ALL THE REGISTERS USED
	POP	BX
	POP	AX
PRI90:
	POP	DS
	IRET				; RETURN WITH INITIAL INTERRUPT MASK
PRINT_SCREEN_1	ENDP

;-----	CARRIAGE RETURN, LINE FEED SUBROUTINE

CRLF	PROC	NEAR
					;	SEND CR,LF TO FIRST PRINTER
	XOR	DX,DX			; ASSUME FIRST PRINTER (DX= 0)
	MOV	AX,CR			; GET THE PRINT CHARACTER COMMAND AND
	INT	17H			;   THE CARRIAGE RETURN CHARACTER
	MOV	AX,LF			; NOW GET THE LINE FEED AND
	INT	17H			;   SEND IT TO THE BIOS PRINTER ROUTINE
	RET
CRLF	ENDP

;----------------------------------------
;	POWER ON RESET VECTOR		:
;----------------------------------------
;	ORG	0FFF0H
	ORG	01FF0H

;-----	POWER ON RESET
P_O_R	LABEL  FAR
	DB	0EAH
	DW	0E05BH			; LOW WORD OF OFFSET
	DW	0F000H			; SEGMENT

	DB	'05/09/86'              ; RELEASE MARKER

;	ORG	0FFFEH
	ORG	01FFEH
MODEL:
	DB	MODEL_BYTE

CODE	ENDS
	END
